基于STM32单片机智能手表手环GSM短信上报GPS定位校时系统设计
- 1、项目简介
- 1.1 系统功能
- 1.2 演示视频
- 2、部分电路设计
- 2.1 STM32单片机核心板电路设计
- 2.2 GPS定位电路设计
- 2.3 SIM900系列短信模块电路
- 2.4 LCD1602液晶显示模块电路设计
- 3、单片机代码展示
- 3.1 系统初始化
- 3.2 LCD1602显示程序
- 3.3 GPS程序
1、项目简介
- 系统构成:
- 本系统由STM32单片机+LCD1602液晶显示、GPS模块、GSM模块、按键、LED灯及电源组成。
1.1 系统功能
- 功能介绍:
- 1、通过GPS定位,获取当前的经纬度信息(可以通过浏览器查看具体位置)。
- 2、液晶LCD1602显示经纬度及时钟、日期,两个信息通过一个按键切换显。如果GPS定位不成功,数据将显示gps link…
- 3、通过电位器可以调节液晶屏的清晰度。
- 4、具有手电筒功能,通过另外一个按键,按下,灯亮,再次按下,灯灭。
- 5、通过第3个按键来发送经纬度信息给人员,按下后,开始发送。
- 6、短信处理过程有指示灯显示。
- 7、人员可以发送"GET"信息给设备手机号,设备解析后,返回相应的数据主要液晶显示数据。
1.2 演示视频
2、部分电路设计
2.1 STM32单片机核心板电路设计
- 基于 ARM Cortex-M3内核的STM32F1系列单片机属于主流STM32单片机,其中增强型STM32F103子系列单片机的CPU 主频高达72MHz,片内Flash容量高达1MB,芯片引脚数量多达144个,有 QFN、LQFP、CSP、BGA 等多种芯片封装形式,并具有多种片内外设、USB接口和CAN 接口。根据STM32F103单片机片内Flash容量的不同,ST 公司将其分为小容量(16-32KB)、中等容量(64-128KB)、大容量(256KB-1MB)3种。
- 电源电路:为单片机提供稳定的工作电压,通常采用3.3V电源供电。电源电路的设计要保证单片机在不同工作条件下都能获得稳定的电压输出,以确保单片机的正常工作。
- 晶振电路:提供单片机工作所需的时钟信号。晶振电路通过晶振和电容组成,为单片机提供稳定的工作脉冲,确保单片机的定时和同步需求。
- 复位电路:实现单片机的复位功能,类似于电脑的重启。复位电路通过电容和电阻的配合,实现单片机在上电启动时的自动复位,以及通过手动按键实现复位功能,保证单片机在程序跑飞或异常情况下能够重新开始执行程序。
STM32单片机是一种功能强大、易于使用、灵活且可靠的32位微控制器,基于ARM Cortex™-M内核。其主要功能特点包括:
- 高性能和低功耗:STM32系列单片机提供多种内核选择,如Cortex-M0、Cortex-M3、Cortex-M4等,满足不同应用场景对性能的需求,同时保持低功耗特性。
- 多种通信和外设接口:STM32单片机具备广泛的通信和外设接口,如I2C、SPI、USART、USB等,便于开发者实现各种复杂功能。
- 易于开发和调试:STM32单片机提供了丰富的软件和硬件工具,如HAL库、CubeMX等,帮助开发者快速创建和调试嵌入式系统。
- 高集成度和设计灵活性:STM32系列单片机全系列产品共用大部分引脚、软件和外设,优异的兼容性为开发人员带来最大的设计灵活性
单片机最小系统原理图如下图所示:
实物图:
2.2 GPS定位电路设计
- 本系统使用的GPS模块均具有高灵敏度、低功耗、小型化、其极高追踪灵敏度大大扩大了其定位的 覆盖面, 在普通GPS 接收模块不能定位的地方, 如狭窄都市天空下、密集的丛林环境, 本系统模块都能高精度定位。模块的高灵敏度、小静态漂移、低功耗及轻巧的体积,适用于车载、手持设备如 PDA,车辆监控、手机、摄像机及其他移动定位系统的应用,是GPS产品应用的最佳选择。
- GPS模块有50个通道的u-blox引擎,1百多万个有效相关器,热启动和辅助启动首次定位时间小于1秒。-162dBm的SuperSense捕获和跟踪灵敏度,具备KickStart功能,型号微弱时可实现加速启动。支持AssistNow Online和AssistNow Offline等A-GPS服务。GPS、GALILEO、SBAS(WAAS、EGNOS、MSAS、GAGAN)混合引擎。
其具体电路原理图如下图所示:
实物图:
2.3 SIM900系列短信模块电路
- GSM模块,是将GSM射频芯片、基带处理芯片、存储器、功放器件等集成在一块线路板上,具有独立的操作系统、GSM射频处理、基带处理并提供标准接口的功能模块。GSM模块具有发送SMS短信,语音通话,GPRS数据传输等基于GSM网络进行通信的所有基本功能。简单来讲,GSM模块加上键盘、显示屏和电池,就是一部手机。
- 工作频段:GSM900/1800MHz。硬件设计在官方设计上加以优化,采用高效开关电源供电,SIM卡采用主流的卡座,质量更坚固。SIM900系列模块在外围硬件的设计上参考了SIM900系列 模块的硬件设计指南,对板子的电源、保护和抗干扰上做足了功夫。电源采用开关电源模块供电,电源利用效率高。
其具体电路原理图如下图所示:
- 实物图:
2.4 LCD1602液晶显示模块电路设计
- LCD显示器分为字段显示和字符显示两种。其中字段显示与LED显示相似,只要送对应的信号到相应的管脚就能显示。字符显示是根据需要显示基本字符。本设计采用的是字符型显示。系统中采用LCD1602作为显示器件输出信息。与传统的LED数码管显示器件相比,液晶显示模块具有体积小、功耗低、显示内容丰富等优点,而且不需要外加驱动电路。
其具体电路原理图如下图所示:
实物图:
3、单片机代码展示
3.1 系统初始化
void HardWare_Init(void)
{
delay_init(); //延时函数初始化
uart_init(115200); //串口初始化为115200
uart2_init(9600) ;
TIM3_Int_Init(499,7199);//50ms
LED_Init(); //初始化与LED连接的硬件接口
KEY_Init();
Lcd_GPIO_init(); //初始化lcd 接口
Lcd_Init(); //初始化函数
}
3.2 LCD1602显示程序
/*--------------------------------------------------
函数说明:写命令到液晶
---------------------------------------------------*/
void LCD_write_cmd(unsigned char cmd)
{
CLR_RS();
LCD_Write_half_byte(cmd >> 4);
LCD_Write_half_byte(cmd);
delay (10000);
}
/*--------------------------------------------------
函数说明:写数据到液晶
---------------------------------------------------*/
void LCD_write_data(unsigned char w_data)
{
SET_RS();
LCD_Write_half_byte(w_data >> 4);
LCD_Write_half_byte(w_data);
delay (10000);
}
/*--------------------------------------------------
函数说明:写4bit到液晶
--------------------------------------------------*/
void LCD_Write_half_byte(unsigned char half_byte)
{
if (half_byte&0x01)
GPIO_SetBits(GPIOB,GPIO_Pin_8);
else
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
if (half_byte&0x02)
GPIO_SetBits(GPIOB,GPIO_Pin_5);
else
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
if (half_byte&0x04)
GPIO_SetBits(GPIOB,GPIO_Pin_6);
else
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
if (half_byte&0x08)
GPIO_SetBits(GPIOB,GPIO_Pin_7);
else
GPIO_ResetBits(GPIOB,GPIO_Pin_7);
SET_EN();
delay(2000);
CLR_EN();
delay(2000);
}
/*----------------------------------------------------
LCD_set_xy : 设置LCD显示的起始位置
输入参数:x、y : 显示字符串的位置,X:1-16,Y:1-2
-----------------------------------------------------*/
void LCD_set_xy( unsigned char x, unsigned char y )
{
unsigned char address;
if (y==1)
{
address=0x80-1+x;
}
else
{
address=0xc0-1+x;
}
LCD_write_cmd(address);
}
/*---------------------------------------------------
LCD_write_string : 英文字符串显示函数
输入参数:*s :英文字符串指针;
X、Y : 显示字符串的位置
---------------------------------------------------*/
void LCD_write_string(unsigned char X,unsigned char Y,unsigned char *s)
{
LCD_set_xy( X, Y );
while (*s)
{
LCD_write_data(*s);
s++;
}
}
void show_str(unsigned char *s)
{ while(*s != '\0')
{
LCD_write_data(*s);
s++;
}
}
void Lcd_Display_22Date(unsigned char line,unsigned char list,unsigned int Date)//用于DS1302显示
{
// unsigned char i;
unsigned char ta[]={0,0,'\0'}; //????????
switch(line){
case 1: LCD_write_cmd(0x80+list);break; //???
case 2: LCD_write_cmd(0xC0+list);break; //???
default : break;
}
ta[0]=Date/16+48;
ta[1]=Date%16+48;
show_str(ta);
}
void Lcd_Display_2Date(unsigned char line,unsigned char list,unsigned int Date)
{
unsigned char i;
unsigned char ta[]={0,0,'\0'}; //????????
switch(line){
case 1: LCD_write_cmd(0x80+list);break; //???
case 2: LCD_write_cmd(0xC0+list);break; //???
default : break;
}
for(i=2;i>0;i--)
{ //??????????????ta
ta[i-1]=Date%10+48;
Date=Date/10;
}
show_str(ta);
}
void Lcd_Display_3Date(unsigned char line,unsigned char list,unsigned int Date)
{
unsigned char i;
unsigned char ta[]={0,0,0,'\0'}; //????????
switch(line){
case 1: LCD_write_cmd(0x80+list);break; //???
case 2: LCD_write_cmd(0xC0+list);break; //???
default : break;
}
for(i=3;i>0;i--)
{ //??????????????ta
ta[i-1]=Date%10+48;
Date=Date/10;
}
show_str(ta);
}
3.3 GPS程序
void dealGps(void)
{
seco_Beijing=(gps_infor_time[4]-0x30)*10+(gps_infor_time[5]-0x30); //提取时间 秒
minu_Beijing=(gps_infor_time[2]-0x30)*10+(gps_infor_time[3]-0x30);//提取时间 分
hour_Beijing=((gps_infor_time[0]-0x30)*10+(gps_infor_time[1]-0x30))+8;//提取时间 小时
days_Beijing=(gps_infor_date[0]-0x30)*10+(gps_infor_date[1]-0x30);//提取时间 天
mont_Beijing=(gps_infor_date[2]-0x30)*10+(gps_infor_date[3]-0x30);//提取时间 月
year_Beijing=(gps_infor_date[4]-0x30)*10+(gps_infor_date[5]-0x30);//提取时间 年
if(hour_Beijing>=24) //北京时间转换
{
hour_Beijing=hour_Beijing%24;
days_Beijing=days_Beijing+1;
if(year_Beijing%4==0)
{
if(days_Beijing>=monthrun_table[mont_Beijing])//天数超过该月份
{
days_Beijing=1;
mont_Beijing++;
if(mont_Beijing>=12)
{
mont_Beijing=1;
year_Beijing++;
}
}
}
if(year_Beijing%4!=0)
{
if(days_Beijing>=monthmon_table[mont_Beijing])//是否夸年
{
days_Beijing=1;
mont_Beijing++;
if(mont_Beijing>=12)
{
mont_Beijing=1;
year_Beijing++;
}
}
}
}
sprintf(dis0,"20%02d-%02d-%02d ",(u16)year_Beijing,(u16)mont_Beijing,(u16)days_Beijing);//打印日期
sprintf(dis1,"%02d:%02d:%02d ",(u16)hour_Beijing,(u16)minu_Beijing,(u16)seco_Beijing);//打印时间
Mid_Du=(gps_infor_weijing[0]-0x30)*10000000+(gps_infor_weijing[1]-0x30)*1000000; //处理经度扩大10000000
Mid_Fen=(gps_infor_weijing[2]-0x30)*10000000+(gps_infor_weijing[3]-0x30)*1000000+
(gps_infor_weijing[4]-0x30)*100000+(gps_infor_weijing[5]-0x30)*10000+
(gps_infor_weijing[6]-0x30)*1000+(gps_infor_weijing[7]-0x30)*100;
Mid_Fen=Mid_Fen/60; //分秒换算为小数位
Mid_Vale=Mid_Du+Mid_Fen; //最终为度格式000.00000000 非度分秒格式
Lin0_No[0]='N';
Lin0_No[1]=':';
Lin0_No[2]='0';
Lin0_No[3]=Mid_Vale/10000000+0x30; //转化为字符
Lin0_No[4]=(Mid_Vale/1000000)%10+0x30;
Lin0_No[5]='.';
Lin0_No[6]=(Mid_Vale/100000)%10+0x30;
Lin0_No[7]=(Mid_Vale/10000)%10+0x30;
Lin0_No[8]=(Mid_Vale/1000)%10+0x30;
Lin0_No[9]=(Mid_Vale/100)%10+0x30;
Lin0_No[10]=(Mid_Vale/10)%10+0x30;
Lin0_No[11]=Mid_Vale%10+0x30;
Mid_Du=(gps_infor_weijing[8]-0x30)*100000000+(gps_infor_weijing[9]-0x30)*10000000+(gps_infor_weijing[10]-0x30)*1000000; //处理经度扩大10000000
Mid_Fen=(gps_infor_weijing[11]-0x30)*10000000+(gps_infor_weijing[12]-0x30)*1000000+
(gps_infor_weijing[13]-0x30)*100000+(gps_infor_weijing[14]-0x30)*10000+
(gps_infor_weijing[15]-0x30)*1000+(gps_infor_weijing[16]-0x30)*100;
Mid_Fen=Mid_Fen/60; //分秒换算为小数位
Mid_Vale=Mid_Du+Mid_Fen; //最终为度格式000.00000000 非度分秒格式
Lin1_Ea[0]='E';
Lin1_Ea[1]=':';
Lin1_Ea[2]=Mid_Vale/100000000+0x30; //转化为字符
Lin1_Ea[3]=(Mid_Vale/10000000)%10+0x30;
Lin1_Ea[4]=(Mid_Vale/1000000)%10+0x30;
Lin1_Ea[5]='.';
Lin1_Ea[6]=(Mid_Vale/100000)%10+0x30;
Lin1_Ea[7]=(Mid_Vale/10000)%10+0x30;
Lin1_Ea[8]=(Mid_Vale/1000)%10+0x30;
Lin1_Ea[9]=(Mid_Vale/100)%10+0x30;
Lin1_Ea[10]=(Mid_Vale/10)%10+0x30;
Lin1_Ea[11]=Mid_Vale%10+0x30;
}