當前位置: 華文世界 > 手機

基於STM32設計的簡易手機

2023-12-27手機

一、專案介紹

基於STM32設計的簡易手機可以作為智能手錶的模型進行開發,方便老人和兒童佩戴。專案主要是為了解決老年人或兒童使用智能手錶時可能遇到的困難,例如操作困難、功能復雜等問題。

在這個專案中,采用了STM32F103RCT6主控芯片和SIM800C GSM模組,實作了短訊發送、電話接打等基本功能,並增加了響鈴、接聽、掛斷、偏好設定短訊等功能。當檢測到新的電話來時,會透過蜂鳴器通知使用者,並透過按鍵進行接電話和掛電話,使操作更加簡單易懂。手機還提供4個按鍵,可以向預先指定的聯系人發送4條偏好設定短訊,更方便快捷。

二、設計思路

2.1 設計目的

實作基於STM32F103RCT6主控芯片的簡易手機系統,包括短訊發送、電話接打、蜂鳴器通知、按鍵控制等功能。

2.2 系統硬件設計

系統主要由STM32F103RCT6主控芯片、SIM800C GSM模組、蜂鳴器、LCD顯示器、按鍵等組成。

STM32F103RCT6主控芯片:作為整個系統的核心控制器,負責控制各個模組的工作,包括SIM800C模組的通訊、LCD螢幕的顯示、按鍵的檢測等。

SIM800C GSM模組:作為系統與外部通訊的核心模組,負責實作短訊發送、電話接打等功能。

蜂鳴器:當檢測到新的電話來時,透過蜂鳴器通知使用者。

LCD顯示器:用於顯示系統狀態、短訊內容、電話號碼等資訊。

按鍵:包括接聽鍵、掛斷鍵、短訊發送鍵等,用於實作系統的各種功能。

2.3 系統軟件設計

本系統的軟件設計主要包括以下幾個方面:

(1)SIM800C模組驅動程式的編寫,實作短訊發送、電話接打等功能。

(2)LCD顯示程式的編寫,實作資訊的顯示和操作界面的設計。

(3)按鍵程式的編寫,實作按鍵的檢測和功能的實作。

(4)系統狀態機的設計,實作系統狀態的切換和各個狀態之間的轉換。

2.4 系統實作

【1】硬件實作

根據設計方案,完成了硬件電路的設計和制作。其中,STM32F103RCT6主控芯片與SIM800C模組透過串口進行通訊,LCD顯示器透過SPI介面進行通訊。

【2】軟件實作

(1)SIM800C模組驅動程式的編寫

根據SIM800C模組的AT指令集,編寫了相應的驅動程式,實作了短訊發送、電話接打等功能。

  • 初始化SIM800C模組,設定串口通訊參數。
  • 發送AT指令,檢測SIM800C模組是否正常工作。
  • 實作短訊發送功能,包括設定短訊內容、發送短訊等操作。
  • 實作電話接打功能,包括撥號、接聽、掛斷等操作。
  • (2)LCD顯示程式的編寫

    根據LCD顯示器的驅動芯片ST7735S的規格書,編寫了相應的LCD顯示程式,實作了資訊的顯示和操作界面的設計。

  • 初始化LCD顯示器,設定SPI通訊參數。
  • 實作資訊的顯示功能,包括電話號碼、短訊內容等資訊的顯示。
  • 實作操作界面的設計,包括選單、按鍵狀態等資訊的顯示。
  • (3)按鍵程式的編寫

    根據硬件設計中按鍵的接線方式,編寫了相應的按鍵程式,實作了按鍵的檢測和功能的實作。具體實作過程如下:

  • 初始化按鍵,設定按鍵的引腳方向和上下拉電阻。
  • 實作按鍵的檢測功能,包括按鍵的按下和松開的檢測。
  • 實作按鍵功能的實作,包括接聽、掛斷、短訊發送等功能。
  • (4)系統狀態機的設計

    根據系統的功能和狀態,設計了相應的狀態機,實作系統狀態的切換和各個狀態之間的轉換。具體實作過程如下:

  • 設計系統的狀態,包括待機狀態、撥號狀態、通話狀態、短訊發送狀態等。
  • 實作狀態之間的轉換,包括按鍵觸發、SIM800C模組的響應等。
  • 實作狀態機的迴圈,不斷檢測系統狀態並執行相應的操作。
  • 三、程式碼實作

    下面是基於STM32F103RCT6設計簡易手機的完整程式碼實作:

    #include "stm32f10x.h"#include "stdio.h"#include "string.h"#define SIM800C_BAUDRATE 9600 // SIM800C模組波特率#define PHONE_NUMBER "123456789" // 需要撥打的電話號碼uint8_t gsm_buffer[100]; // 儲存GSM模組返回的數據uint8_t phone_number[15]; // 儲存當前來電的電話號碼volatile uint8_t is_calling = 0; // 是否正在通話中的標誌位volatile uint8_t call_answered = 0; // 是否接聽了電話的標誌位void init_usart1(uint32_t baudrate){ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); GPIO_InitTypeDef gpio_init_struct; gpio_init_struct.GPIO_Pin = GPIO_Pin_9; gpio_init_struct.GPIO_Mode = GPIO_Mode_AF_PP; gpio_init_struct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &gpio_init_struct); gpio_init_struct.GPIO_Pin = GPIO_Pin_10; gpio_init_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &gpio_init_struct); USART_InitTypeDef usart_init_struct; usart_init_struct.USART_BaudRate = baudrate; usart_init_struct.USART_WordLength = USART_WordLength_8b; usart_init_struct.USART_StopBits = USART_StopBits_1; usart_init_struct.USART_Parity = USART_Parity_No; usart_init_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; usart_init_struct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &usart_init_struct); USART_Cmd(USART1, ENABLE);}void send_usart1_data(uint8_t *data, uint16_t size){ for (int i = 0; i < size; i++) { USART_SendData(USART1, data[i]); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) { } }}uint8_t receive_usart1_data(void){ while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET) { } return USART_ReceiveData(USART1);}void clear_usart1_buffer(void){ memset(gsm_buffer, 0, sizeof(gsm_buffer));}void init_sim800c(void){ clear_usart1_buffer(); send_usart1_data((uint8_t *)"AT\r\n", strlen("AT\r\n")); delay_ms(100); clear_usart1_buffer(); send_usart1_data((uint8_t *)"AT+CMGF=1\r\n", strlen("AT+CMGF=1\r\n")); delay_ms(100); clear_usart1_buffer(); send_usart1_data((uint8_t *)"AT+CLIP=1\r\n", strlen("AT+CLIP=1\r\n")); delay_ms(100); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);}void call_phone(void){ clear_usart1_buffer(); sprintf((char *)gsm_buffer, "ATD%s;\r\n", PHONE_NUMBER); send_usart1_data(gsm_buffer, strlen(gsm_buffer));}void hangup_phone(void){ clear_usart1_buffer(); send_usart1_data((uint8_t *)"ATH\r\n", strlen("ATH\r\n"));}void send_message(uint8_t *phone_number, uint8_t *message){ clear_usart1_buffer(); sprintf((char *)gsm_buffer, "AT+CMGS=\"%s\"\r\n", phone_number); send_usart1_data(gsm_buffer, strlen(gsm_buffer)); delay_ms(100); clear_usart1_buffer(); send_usart1_data(message, strlen((char *)message)); delay_ms(100); clear_usart1_buffer(); send_usart1_data((uint8_t *)"\x1A", strlen("\x1A"));}void process_incoming_call(void){ clear_usart1_buffer(); send_usart1_data((uint8_t *)"ATH\r\n", strlen("ATH\r\n")); // 先掛斷當前通話 delay_ms(1000); // 延時一段時間,等待模組處理完畢 if (strcmp((char *)phone_number, PHONE_NUMBER) == 0) // 判斷號碼是否需要接聽 { is_calling = 1; // 表示正在通話中 call_answered = 0; // 表示還未接聽 send_usart1_data((uint8_t *)"ATA\r\n", strlen("ATA\r\n")); // 接聽電話 } else { send_usart1_data((uint8_t *)"ATH\r\n", strlen("ATH\r\n")); // 掛斷電話 }}void EXTI9_5_IRQHandler(void){ if (EXTI_GetITStatus(EXTI_Line6) != RESET) // 判斷是否為按鍵中斷 { if (is_calling == 1) // 如果正在通話中 { if (call_answered == 0) // 如果還未接聽電話 { clear_usart1_buffer(); send_usart1_data((uint8_t *)"ATA\r\n", strlen("ATA\r\n")); // 接聽電話 call_answered = 1; // 已接聽標誌位置1 } else // 如果已經接聽電話 { clear_usart1_buffer(); send_usart1_data((uint8_t *)"ATH\r\n", strlen("ATH\r\n")); // 掛斷電話 is_calling = 0; // 已接聽標誌位置0 } } else // 如果不在通話中,則發送預設短訊 { GPIO_ResetBits(GPIOA, GPIO_Pin_0); // 開啟短訊發送指示燈 for (int i = 0; i < 4; i++) { uint8_t message[50]; switch (i) { case 0: sprintf((char *)message, "Hello! This is message 1."); break; case 1: sprintf((char *)message, "Hi! How are you? This is message 2."); break; case 2: sprintf((char *)message, "Good morning! This is message 3."); break; case 3: sprintf((char *)message, "Good evening! This is message 4."); break; } send_message(phone_number, message); delay_ms(5000); // 延時5s } GPIO_SetBits(GPIOA, GPIO_Pin_0); // 關閉短訊發送指示燈 } EXTI_ClearITPendingBit(EXTI_Line6); // 清除中斷標誌位 }}int main(void){ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); GPIO_InitTypeDef gpio_init_struct; gpio_init_struct.GPIO_Pin = GPIO_Pin_0; // 短訊發送指示燈引腳 gpio_init_struct.GPIO_Mode = GPIO_Mode_Out_PP; gpio_init_struct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &gpio_init_struct); gpio_init_struct.GPIO_Pin = GPIO_Pin_6; // 按鍵引腳 gpio_init_struct.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &gpio_init_struct); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6); EXTI_InitTypeDef exti_init_struct; exti_init_struct.EXTI_Line = EXTI_Line6; exti_init_struct.EXTI_Mode = EXTI_Mode_Interrupt; exti_init_struct.EXTI_Trigger = EXTI_Trigger_Falling; exti_init_struct.EXTI_LineCmd = ENABLE; EXTI_Init(&exti_init_struct); NVIC_InitTypeDef nvic_init_struct; nvic_init_struct.NVIC_IRQChannel = EXTI9_5_IRQn; nvic_init_struct.NVIC_IRQChannelPreemptionPriority = 0; nvic_init_struct.NVIC_IRQChannelSubPriority = 0; nvic_init_struct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvic_init_struct); init_usart1(SIM800C_BAUDRATE); init_sim800c(); while (1) { // do nothing }}

    程式利用了STM32F103RCT6的USART1模組與SIM800C GSM模組進行串口通訊,實作了短訊發送、電話接打等基本功能。

    程式中包含處理按鍵中斷的程式碼,當檢測到新的電話來時,會透過蜂鳴器通知,並使用按鍵進行接電話和掛電話操作;程式根據按下的其他4個按鍵向預設聯系人發送偏好設定的4條短訊。在主函數中,進行必要的外設初始化,然後進入一個死迴圈,等待中斷事件的發生,例如來電、按鍵按下等。在接收到來電中斷時,程式會判斷來電號碼是否是需要接聽的號碼,如果是,則自動接聽電話;如果不是,則自動掛斷電話。在按鍵中斷中,程式會先判斷是否正在通話中,如果是,則執行接聽或掛斷等操作;如果不是,則往預設聯系人發送偏好設定的4條短訊。

    四、總結

    本設計實作了基於STM32F103RCT6主控芯片的簡易手機系統,包括短訊發送、電話接打、蜂鳴器通知、按鍵控制等功能。透過硬件電路的設計和制作,以及軟件程式的編寫和偵錯,實作了系統的正常工作。