写点什么

基于 STM32 设计的简易手机

作者:DS小龙哥
  • 2024-08-16
    重庆
  • 本文字数:5017 字

    阅读完需:约 16 分钟

一、项目介绍

基于 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 主控芯片的简易手机系统,包括短信发送、电话接打、蜂鸣器通知、按键控制等功能。通过硬件电路的设计和制作,以及软件程序的编写和调试,实现了系统的正常工作。

发布于: 11 分钟前阅读数: 5
用户头像

DS小龙哥

关注

微信公众号:DS小龙哥嵌入式技术资讯 2022-01-06 加入

所有项目文章对应的工程源码,都可以在我的微信公众号:《DS小龙哥嵌入式技术资讯》 里下载。

评论

发布
暂无评论
基于STM32设计的简易手机_8月月更_DS小龙哥_InfoQ写作社区