一、项目介绍
基于 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 指令集,编写了相应的驱动程序,实现了短信发送、电话接打等功能。
(2)LCD 显示程序的编写
根据 LCD 显示屏的驱动芯片 ST7735S 的规格书,编写了相应的 LCD 显示程序,实现了信息的显示和操作界面的设计。
(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 主控芯片的简易手机系统,包括短信发送、电话接打、蜂鸣器通知、按键控制等功能。通过硬件电路的设计和制作,以及软件程序的编写和调试,实现了系统的正常工作。
评论