一、项目介绍
基于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设计简易手机的完整代码实现:
cpp
#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 ", strlen("AT "));
delay_ms(100);
clear_usart1_buffer();
send_usart1_data((uint8_t *)"AT+CMGF=1 ", strlen("AT+CMGF=1 "));
delay_ms(100);
clear_usart1_buffer();
send_usart1_data((uint8_t *)"AT+CLIP=1 ", strlen("AT+CLIP=1 "));
delay_ms(100);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}
void call_phone(void)
{
clear_usart1_buffer();
sprintf((char *)gsm_buffer, "ATD%s; ", PHONE_NUMBER);
send_usart1_data(gsm_buffer, strlen(gsm_buffer));
}
void hangup_phone(void)
{
clear_usart1_buffer();
send_usart1_data((uint8_t *)"ATH ", strlen("ATH "));
}
void send_message(uint8_t *phone_number, uint8_t *message)
{
clear_usart1_buffer();
sprintf((char *)gsm_buffer, "AT+CMGS="%s" ", 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 ", strlen("ATH ")); // 先挂断当前通话
delay_ms(1000); // 延时一段时间,等待模块处理完毕
if (strcmp((char *)phone_number, PHONE_NUMBER) == 0) // 判断号码是否需要接听
{
is_calling = 1; // 表示正在通话中
call_answered = 0; // 表示还未接听
send_usart1_data((uint8_t *)"ATA ", strlen("ATA ")); // 接听电话
}
else
{
send_usart1_data((uint8_t *)"ATH ", strlen("ATH ")); // 挂断电话
}
}
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 ", strlen("ATA ")); // 接听电话
call_answered = 1; // 已接听标志位置1
}
else // 如果已经接听电话
{
clear_usart1_buffer();
send_usart1_data((uint8_t *)"ATH ", strlen("ATH ")); // 挂断电话
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); // 清除中断标志位
}