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

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