思路:
寄件:验证数字密码锁:成功则随机开启锁 进行寄件 产生随机码 保存 给指定手机号发送取件码
取件:输入取件码取件
主界面:
/*
*@auth:火红色祥云
*@time:2020-01-27 18-48-27
*@E-mail:201926154@qq.com
*/
char Init_Buffer[5]="0000";//用于清空盒子
int main(void)
{
int i;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Key_Config();
Box_Init();
OLED_Init();
uart_init(115200);
TIM3_Int_Init(4999,7199);//用于产生随机数的种子系数
AT24CXX_Init(); //IIC初始化
usart3_init(115200); //sim800c
initUART2();//服务器串口初始化
/*清空取件码的空间*/
for(i=0;i<5;i++)
{
AT24CXX_Write(i*5,"0000",5);
}
/*初始化服务器,服务器自检*/
OLED_ShowString(0,0,"WiFiServerCheck");
if(initESP8266()!=0)
OLED_ShowString(0,2,"Init OK!");
else
OLED_ShowString(0,2,"Init ERROR!");
if(connectAP(SSID,PWD,defaltIP)!=0)
OLED_ShowString(0,4,"Connect AP OK!");
else
OLED_ShowString(0,4,"Con AP ERROR!");
if(CreatServer()!=0)
OLED_ShowString(0,6,"Creat AP OK!");
else
OLED_ShowString(0,6,"Creat AP ERROR!");
delay_ms(500);
OLED_Clear();
/*初始化服务器,服务器自检*/
while(1)
{
int num0=0,EmpBoxNum;
ProServerDate();//等待手机端的验证码
EmpBoxNum=EmptyBox();
OLED_ShowString(0,0," SmartExpress ");
OLED_ShowString(0,2,"EmptyBox:");
OLED_ShowNum(80,2,EmpBoxNum,1,16);
OLED_ShowString(0,4,"KEY13:Save");
OLED_ShowString(0,6,"KEY15:Get");
num0=KeyScan();
if(num0)
{
switch(num0)
{
case 13:SaveExpress();
break;
case 15:GetExpress();
break;
default:
break;
}
}
}
}
第一部分:矩阵键盘
/**
** PF12-15,列,输出。 PF8-PB11,行,输入
**左侧从下至上依次8-15
**/
void Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);
/********4行输出*********/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOF, &GPIO_InitStructure);
/********4列输入*********/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOF, &GPIO_InitStructure);
}
int KeyScan(void)
{
uchar KeyVal;
GPIO_Write(GPIOF,((GPIOF->ODR&0xf0ff)|0x0f00)); //不管其余12位0xf0ff,先让PF8到PF11全部输出高。
if((GPIOF->IDR&0xf000)==0x0000) //如果PF12到PF15全为零则没有按键按下
return 0;
else
{
delay_ms(5); //延时5ms去抖动
if((GPIOF->IDR&0xf000)==0x0000)
return 0;
}
GPIO_Write(GPIOF,((GPIOF->ODR&0xf0ff)|0x0100)); //仅将PF8置高
switch(GPIOF->IDR&0xf000) //第一行,由低到高,同理,不赘述
{
case 0x1000: KeyVal=13; break;
case 0x2000: KeyVal=14; break;
case 0x4000: KeyVal=15; break;
case 0x8000: KeyVal=16; break;
}
while((GPIOF->IDR&0xf000)>0); //等待按键释放
GPIO_Write(GPIOF,((GPIOF->ODR&0xf0ff)|0x0200)); //仅将PF9置高
switch(GPIOF->IDR & 0xf000)
{
case 0x1000: KeyVal=9; break;
case 0x2000: KeyVal=10; break;
case 0x4000: KeyVal=11; break;
case 0x8000: KeyVal=12; break;
}
while((GPIOF->IDR & 0xf000)>0);
GPIO_Write(GPIOF,((GPIOF->ODR&0xf0ff)|0x0400)); //仅将PF10置高
switch(GPIOF->IDR & 0xf000)
{
case 0x1000: KeyVal=5; break;
case 0x2000: KeyVal=6; break;
case 0x4000: KeyVal=7; break;
case 0x8000: KeyVal=8; break;
}
while((GPIOF->IDR & 0xf000)>0);
GPIO_Write(GPIOF,((GPIOF->ODR&0xf0ff)|0x0800)); //仅将PF11置高
switch(GPIOF->IDR&0xf000)
{
case 0x1000: KeyVal=1; break;
case 0x2000: KeyVal=2; break;
case 0x4000: KeyVal=3; break;
case 0x8000: KeyVal=4; break;
}
while((GPIOF->IDR&0xf000)>0);
return KeyVal;
}
第二部分:ESP8266驱动部分(USART2)
/*.h*/
/*连接AP宏定义*/
#define SSID "qq"
#define PWD "qwertyuiop789000"
#define defaltIP "192.168.137.111"
/*发送接收缓冲区长度宏定义*/
#define TXBUFFER_LEN 50
#define RXBUFFER_LEN 30
/*.c*/
u8 TXBuffer[TXBUFFER_LEN] = {0}; //网络通信数据发送缓冲
u8 RXBuffer[RXBUFFER_LEN] = {0}; //网络通信数据接收缓冲
char empty_buffer[5]="0000";//用于清空盒子,下次使用
/**
* 功能:外设串口初始化
* 参数:
* 无
*/
void initUART2(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/*配置USART2和GPIO时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
/*GPIO配置*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* UART2配置 */
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
//定义NVIC初始化结构体
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //指定配置的中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //设置子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使/失能中断
NVIC_Init(&NVIC_InitStructure);
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
}
/**
* 功能:指定某个UART发送一个字节
* 参数:USARTx:使用的目标串口x为1-3
* byte:待发送字节
* 返回值:None
*/
static void sendByte(USART_TypeDef *USARTx, u16 byte)
{
USART_ClearFlag(USARTx, USART_FLAG_TC); //软件清除发送完成标志位
USART_SendData(USARTx, byte); //发送一个字节
while (!USART_GetFlagStatus(USARTx, USART_FLAG_TC));//等待发送完成
USART_ClearFlag(USARTx, USART_FLAG_TC); //软件清除发送完成标志位
}
/**
* 功能:指定某个串口发送字符串
* 参数:USARTx:使用的目标串口x为1-3
* str:字符串指针
* 返回值:None
*/
void sendString(USART_TypeDef *USARTx, char *str)
{
while (*str)
{
sendByte(USARTx,*str++);
}
}
/**
* 功能:串口2中断服务函数
* 参数:None
* 返回值:None
*/
void USART2_IRQHandler(void)
{
static u8 i = 0;
if(USART_GetITStatus(USART2, USART_IT_RXNE)) //判断接收数据寄存器是否有数据
{
RXBuffer[i++] = USART_ReceiveData(USART2);
if(i==RXBUFFER_LEN) //超出接收缓冲范围,可能的情形是ESP8266复位,为防止溢出必须设置索引
{
i = RXBUFFER_LEN-1;
}
}
if(USART_GetITStatus(USART2, USART_IT_IDLE))
{
USART_ReceiveData(USART2); //读一次UART可以清除空闲标志位
i = 0;
}
}
/**
* 功能:查找字符串中是否包含另一个字符串
* 参数:
* dest:待查找目标字符串
* src:待查找内容
* retry_cn:查询超时时间
* 返回值:查找结果,非0为查找成功,0为失败
* 说明:
* 当发出一个AT指令后,需要一段时间等待ESP8266回复,因此就需要等待一段时间,
* 这个时间通常是几百ms(除了连接服务器和AP指令),本程序一般指令通常等待
* 2S,耗时的连接AP和服务器的设置等待为8S,其实花不了那么多时间,但如果发生超时
* 就一定可以判断是通信问题
*/
u8 findStr(u8* dest,u8* src,u16 retry_cn)
{
u16 retry = retry_cn; //超时时间
u8 result_flag = 0; //查找结果
while(strstr((char*)dest,(char*)src)==0 && --retry!=0)//等待串口接收完毕或超时退出
{
delay_ms(10);
}
if(retry==0) //如果超时则有问题,此时返回0
{
return 0;
}
result_flag = 1; //执行到这里说明一切正常, 表示查找成功
if(result_flag)
{
return 1;
}else
{
return 0;
}
}
/**
* 功能:初始化ESP8266
* 参数:None
* 返回值:初始化结果,非0为初始化成功,0为失败
*/
u8 initESP8266(void)
{
sendString(USART2,"+++"); //退出透传
delay_ms(500);
sendString(USART2,"AT+RST\r\n"); //重启ESP8266
delay_ms(500);
if(checkESP8266()==0) //使用AT指令检查ESP8266是否存在
{
return 0;
}
memset(RXBuffer,0,RXBUFFER_LEN); //清空接收缓冲
sendString(USART2,"ATE0\r\n"); //关闭回显
if(findStr(RXBuffer,"OK",200)==0) //设置不成功
{
return 0;
}
return 1; //设置成功
}
/**
* 功能:恢复出厂设置
* 参数:None
* 返回值:None
* 说明:此时ESP8266中的用户设置将全部丢失回复成出厂状态
*/
void restoreESP8266(void)
{
sendString(USART2,"+++"); //退出透传
delay_ms(500);
sendString(USART2,"AT+RESTORE\r\n");//恢复出厂
NVIC_SystemReset(); //同时重启单片机
}
/**
* 功能:检查ESP8266是否正常
* 参数:None
* 返回值:ESP8266返回状态
* 非0 ESP8266正常
* 0 ESP8266有问题
*/
u8 checkESP8266(void)
{
memset(RXBuffer,0,RXBUFFER_LEN); //清空接收缓冲
sendString(USART2,"AT\r\n"); //发送AT握手指令
if(findStr(RXBuffer,"OK",200)!=0)//ESP8266正常
{
return 1;
}else //ESP8266不正常
{
return 0;
}
}
/**
* 功能:连接热点
* 参数:
* ssid:热点名
* pwd:热点密码
* 返回值:
* 连接结果,非0连接成功,0连接失败
* 说明:
* 失败的原因有以下几种(UART通信和ESP8266正常情况下)
* 1. WIFI名和密码不正确
* 2. 路由器连接设备太多,未能给ESP8266分配IP
*/
u8 connectAP(u8* ssid,u8* pwd,u8* defaltip)
{
memset(RXBuffer,0,RXBUFFER_LEN);
sendString(USART2,"AT+CWMODE?\r\n"); //查询此时WIFI工作模式
if(findStr(RXBuffer,"CWMODE:1",200)==0) //如果此时不是MODE1模式,即不是STATION模式
{
memset(RXBuffer,0,RXBUFFER_LEN);
sendString(USART2,"AT+CWMODE=1\r\n"); //设置为STATION模式
if(findStr(RXBuffer,"OK",200)==0)
{
return 0;
}
}
memset(TXBuffer,0,RXBUFFER_LEN); //清空发送缓冲
memset(RXBuffer,0,RXBUFFER_LEN); //清空接收缓冲
sprintf((char*)TXBuffer,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,pwd);//连接目标AP
sendString(USART2,(char*)TXBuffer);
if(findStr(RXBuffer,"OK",800)!=0) //连接成功且分配到IP
{
memset(TXBuffer,0,RXBUFFER_LEN); //清空发送缓冲
memset(RXBuffer,0,RXBUFFER_LEN); //清空接收缓冲
sprintf((char*)TXBuffer,"AT+CIPSTA=\"%s\"\r\n",defaltIP);//设置默认IP
sendString(USART2,(char*)TXBuffer);
if(findStr(RXBuffer,"OK",800)!=0)
return 1;
else
return 0;
}
return 0;
}
/**
* 功能:连接热点
* 参数:
* ssid:热点名
* pwd:热点密码
* 返回值:
* 连接结果,非0连接成功,0连接失败
* 说明:
* 失败的原因有以下几种(UART通信和ESP8266正常情况下)
* 1. WIFI名和密码不正确
* 2. 路由器连接设备太多,未能给ESP8266分配IP
*/
u8 CreatServer(void)
{
memset(RXBuffer,0,RXBUFFER_LEN);
sendString(USART2,"AT+CIPMUX=1\r\n"); //设置建立一个TCP服务器
if(findStr(RXBuffer,"OK",200)!=0) //如果此时不是MODE1模式,即不是STATION模式
{
memset(RXBuffer,0,RXBUFFER_LEN);
sendString(USART2,"AT+CIPSERVER=1,8080\r\n");//开启TCP Server ,端口设置为8080
if(findStr(RXBuffer,"OK",200)!=0)
return 1;
else
return 0;
}
else
return 0;
}
/**
* 功能:处理从手机端接收的控制数据
* 参数:24C02中的验证码
* 返回值:None
* 说明:
*/
void ProServerDate()
{
int match,boxID;
u8 codenum[5]={"9999"};
u8 boxadd[2];
for(match=0;match<5;match++)
{
AT24CXX_Read(match*5,codenum,5);//读取取件码,此时取件码为字符串数字
if((char*)strstr((char*)RXBuffer,(char*)codenum))//匹配成功
{
memset(RXBuffer,0,RXBUFFER_LEN);//清空接受缓存
AT24CXX_Read(match*2+30,boxadd,2);//读取BoxID,此时ID为字符串数字
boxID=atoi((char*)boxadd); //把字符串数字转化为整型数字
OLED_Clear();
OLED_ShowString(0,0,"OpenBoxID:");
OLED_ShowNum(0,2,boxID+1,3,16);
OLED_ShowString(0,6,"TakeAwayPack");
//打开对应门锁
switch(boxID)
{
case 0:
Box0=1;//打开第1个快递箱
delay_ms(1000);
Box0=0;//拉低电平,放入完毕后手动上锁
AT24CXX_Write(boxID*5,(u8*)empty_buffer,5);//清空已取走快递的取件码
break;
case 1:
Box1=1;//打开第2个快递箱
delay_ms(1000);
Box1=0;//拉低电平,放入完毕后手动上锁
AT24CXX_Write(boxID*5,(u8*)empty_buffer,5);//清空已取走快递的取件码
break;
case 2:
AT24CXX_Write(boxID*5,(u8*)empty_buffer,5);//清空已取走快递的取件码
break;
case 3:
AT24CXX_Write(boxID*5,(u8*)empty_buffer,5);//清空已取走快递的取件码
break;
case 4:
AT24CXX_Write(boxID*5,(u8*)empty_buffer,5);//清空已取走快递的取件码
break;
default:break;
}
delay_ms(500);
OLED_Clear();
}
}
}
第三部分:Random随机数产生部分(定时器用来产生随机数的种子)
#include "random.h"
#include "usart.h"
#include "stdlib.h"
int times=0;
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
times+=50;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
if(times==10000)
times=0;
}
}
int GreatCode(void)
{
int randcode;//产生的随机数
srand(times);//随机数的种子系数
randcode=rand()%9000+1000; //生成1000-9999范围的随机数rand()%(b-a+1)+a,范围:(a,b)
return randcode;
}
第四部分:SIM8000C发送短信驱动部分(USART3)
/*USART3驱动*/
/*.h*/
#define USART3_MAX_RECV_LEN 600 //最大接收缓存字节数
#define USART3_MAX_SEND_LEN 600 //最大发送缓存字节数
#define USART3_RX_EN 1 //0,不接收;1,接收.
extern u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN字节
extern u8 USART3_TX_BUF[USART3_MAX_SEND_LEN]; //发送缓冲,最大USART3_MAX_SEND_LEN字节
extern vu16 USART3_RX_STA; //接收数据状态
void usart3_init(u32 bound); //串口2初始化
void u3_printf(char* fmt,...);
/*.c*/
//串口接收缓存区
u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
u8 USART3_TX_BUF[USART3_MAX_SEND_LEN]; //发送缓冲,最大USART3_MAX_SEND_LEN字节
//蓝牙扫描下: timer=1S
//非蓝牙扫描下: timer=10ms
//通过判断接收连续2个字符之间的时间差不大于timer来决定是不是一次连续的数据.
//如果2个字符接收间隔超过timer,则认为不是1次连续数据.也就是超过timer没有接收到
//任何数据,则表示此次接收完毕.
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
vu16 USART3_RX_STA=0;
void USART3_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据
{
res =USART_ReceiveData(USART3);
if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
{
if(USART3_RX_STA<USART3_MAX_RECV_LEN) //还可以接收数据
{
TIM_SetCounter(TIM7,0); //计数器清空
if(USART3_RX_STA==0) //使能定时器7的中断
{
TIM_Cmd(TIM7,ENABLE); //使能定时器7
}
USART3_RX_BUF[USART3_RX_STA++]=res; //记录接收到的值
}else
{
USART3_RX_STA|=1<<15; //强制标记接收完成
}
}
}
}
//初始化IO 串口3
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率
void usart3_init(u32 bound)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3时钟使能
USART_DeInit(USART3); //复位串口3
//USART3_TX PB10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10
//USART3_RX PB11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB11
USART_InitStructure.USART_BaudRate = bound; //波特率一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART3, &USART_InitStructure); //初始化串口3
USART_Cmd(USART3, ENABLE); //使能串口
//使能接收中断
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); //开启中断
//设置中断优先级
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
TIM7_Int_Init(99,7199); //10ms中断
USART3_RX_STA=0; //清零
TIM_Cmd(TIM7,DISABLE); //关闭定时器7
}
//串口3,printf 函数
//确保一次发送数据不超过USART3_MAX_SEND_LEN字节
void u3_printf(char* fmt,...)
{
u16 i,j;
va_list ap;
va_start(ap,fmt);
vsprintf((char*)USART3_TX_BUF,fmt,ap);
va_end(ap);
i=strlen((const char*)USART3_TX_BUF); //此次发送数据的长度
for(j=0;j<i;j++) //循环发送数据
{
while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕
USART_SendData(USART3,USART3_TX_BUF[j]);
}
}
/*sim800c驱动*/
u8 flag=0;
//SIM800C发送命令后,检测接收到的应答
//str:期待的应答结果
//返回值:0,没有得到期待的应答结果
//其他,期待应答结果的位置(str的位置)
u8* sim800c_check_cmd(u8 *str)
{
char *strx=0;
if(USART3_RX_STA&0X8000) //接收到一次数据了
{
USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
strx=strstr((const char*)USART3_RX_BUF,(const char*)str);
}
return (u8*)strx;
}
//SIM800C发送命令
//cmd:发送的命令字符串(不需要添加回车了),当cmd<0XFF的时候,发送数字(比如发送0X1A),大于的时候发送字符串.
//ack:期待的应答结果,如果为空,则表示不需要等待应答
//waittime:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果)
// 1,发送失败
u8 sim800c_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
{
u8 res=0;
USART3_RX_STA=0;
if((u32)cmd<=0XFF)
{
while((USART3->SR&0X40)==0);//等待上一次数据发送完成
USART3->DR=(u32)cmd;
}else u3_printf("%s\r\n",cmd);//发送命令
if(ack&&waittime) //需要等待应答
{
while(--waittime) //等待倒计时
{
delay_ms(10);
if(USART3_RX_STA&0X8000)//接收到期待的应答结果
{
if(sim800c_check_cmd(ack))break;//得到有效数据
USART3_RX_STA=0;
}
}
if(waittime==0)res=1;
}
return res;
}
//接收SIM800C返回数据(蓝牙测试模式下使用)
//request:期待接收命令字符串
//waittimg:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果)
// 1,发送失败
u8 sim800c_wait_request(u8 *request ,u16 waittime)
{
u8 res = 1;
if(request && waittime)
{
while(--waittime)
{
if(USART3_RX_STA &0x8000)//接收到期待的应答结果
{
if(sim800c_check_cmd(request)) break;//得到有效数据
USART3_RX_STA=0;
}
}
if(waittime==0)res=0;
}
return res;
}
void sim_send_sms(int code)
{
u8 pn[11];
u8 pnstr[11]="";
u8 key=0,pnum,pnlen=0;
u8 cmdstr[30]="";
u8 codestr[5]="";
OLED_Clear();
OLED_ShowString(0,0,"InputPhoneNum:");
while(1)
{
key=KeyScan();
if(key==16)
{
pnlen=0;
break;
}
if(key)
{
switch(key)
{
case 1:pnum=1;break;
case 2:pnum=2;break;
case 3:pnum=3;break;
case 5:pnum=4;break;
case 6:pnum=5;break;
case 7:pnum=6;break;
case 9:pnum=7;break;
case 10:pnum=8;break;
case 11:pnum=9;break;
case 14:pnum=0;break;
default:flag=1;break;
}
if(flag==0)
{
pn[pnlen]=pnum;
OLED_ShowNum(pnlen*8,2,pnum,1,16);
pnlen++;
flag=1;
}
if(pnlen==11)
{
sprintf((char*)pnstr,"%d%d%d%d%d%d%d%d%d%d%d",pn[0],pn[1],pn[2],pn[3],pn[4],pn[5],pn[6],pn[7],pn[8],pn[9],pn[10]);
pnlen=0;
break;
}
}
else
{
delay_ms(10);
flag=0;//放手时,归零以便下次重新计数
}
}
OLED_Clear();
if(sim800c_send_cmd("AT","OK",200)==0)//测试
{
OLED_ShowString(0,0,"Init 1th Step OK");
}
if(sim800c_send_cmd("AT+CMGF=1","OK",200)==0)//设置文本模式
{
OLED_ShowString(0,2,"Init 2th Step OK");
}
if(sim800c_send_cmd("AT+CSCS=\"GSM\"","OK",200)==0)//设置GSM模式
{
OLED_ShowString(0,4,"Init 3th Step OK");
}
sprintf((char*)cmdstr,"AT+CMGS=\"%s\"",pnstr);
if(sim800c_send_cmd(cmdstr,">",200)==0) //发送短信命令+电话号码
{
sprintf((char*)codestr,"Your Code is:%d",code);
u3_printf("%s",codestr); //发送短信内容到GSM模块
if(sim800c_send_cmd((u8*)0X1A,"+CMGS:",1000)==0)//发送结束符,等待发送完成(最长等待10秒钟,因为短信长了的话,等待时间会长一些)
{
OLED_ShowString(0,6,"Send Successful!");
}
else
{
OLED_ShowString(0,6,"Send Failed!");
}
USART3_RX_STA=0;
}
delay_ms(1000);
}
/*定时器驱动(蓝牙用的)*/
extern vu16 USART3_RX_STA;
//配置TIM7预装载周期值
void TIM7_SetARR(u16 period)
{
TIM_SetCounter(TIM7,0);//计数器清空
TIM7->ARR&=0x00;//先清预装载周期值为0
TIM7->ARR|= period;//更新预装载周期值
}
//定时器7中断服务程序
void TIM7_IRQHandler(void)
{
if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)//是更新中断
{
TIM_ClearITPendingBit(TIM7, TIM_IT_Update ); //清除TIM7更新中断标志
USART3_RX_STA|=1<<15; //标记接收完成
TIM_Cmd(TIM7, DISABLE); //关闭TIM7
}
}
//通用定时器7中断初始化
//这里时钟选择为APB1的2倍,而APB1为42M
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
//通用定时器中断初始化
//这里始终选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
void TIM7_Int_Init(u16 arr,u16 psc)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//TIM7时钟使能
//定时器TIM7初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE ); //使能指定的TIM7中断,允许更新中断
TIM_Cmd(TIM7,ENABLE);//开启定时器7
NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}