一:任意字节串口接收实现
(1)可以参考我的另一篇博客:http://t.csdnimg.cn/KUAvc 第三部分的串口中断接收
(2)在这串口中断接收回调函数里需要有一个细微的变化
1:原串口接收回调函数内是先设置一个数据缓冲区
2:然后在main函数内调用串口中断接收函数使用串口1中断接收5个字节数据以及调用串口中断使能函数使能串口1中断
3:主函数内部while循环是没做任何操作的
4 :设置串口回调函数,当发生串口时,将串口中断接收到的数据通过串口1发送5个字节数据回去并且重新打开串口1中断接收
5: 串口接收进行微小的改变,数据接收缓存区数据改成uint8_t类型的全局变量
6:main函数内部中断接收改为将数据存放到uint8_t类型的全局变量ch中,接收一个字节的数据因为是uint8_t的全局变量所以不是指针指向数据首元素首地址,而是使用取地址符将数据存放到编译器给全局变量ch分配的地址处
7:修改回调函数一些细节
二:基于串口命令shell实现
(1)协议自定义,首先通信双方需要定义协议
(2)定义一套指令集,指令1、指令2。。。。。。。
(3)指令结束符:';'
(4)指令中遇到回车、空格、TAB等特殊字符怎么办?(这里先不管)
三:PC端通过usb转串口模块给单片机发指令,单片机接受指令并执行
1:工程创建
流程:打开stm32cubemx ->选择芯片 ->选择仿真接口->配置时钟 ->配置串口 ->开启中断->设置工程c名 ->生成工程
详情见另一篇博客 :http://t.csdnimg.cn/NwN3W
2:代码编写
定义全局变量 ch 用来接收字节数据 dataval 用来接收完整指令 flag 用来做dataval的索引
在进入主函数未进行while循环时 先调用一次串口中断接收
串口回调函数 当接收到从pc端来的数据时进入这个函数 对数据进行处理
/*********************************************************************
函数名:HAL_UART_RxCpltCallback
作用:串口回调函数,串口接收中断后进入这个函数
参数:无
返回值:无
无需调用这个函数,串口数据进行接收后会自动进入这个函数内
**********************************************************************/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
// 接收到数据后,对数据进行处理
dataval[flag++] = ch;
//等待本次接受完毕重新启用串口中断接收
while(HAL_UART_Receive_IT(&huart1,&ch,1) != HAL_OK);
}
}
main 函数内部 while循环内代码
for(uint16_t i = 0;i<flag;i++)
{
if(dataval[i] == ';')
{
if( strcmp( (const char *)dataval,(const char *)"aaa;" ) == 0 )
{
printf("zhiling1");
memset(dataval,0,20); //清除数据接收缓存区
flag = 0;
}
else if( strcmp( (const char *)dataval,(const char *)"bbb;" ) == 0 )
{
printf("zhiling2");
memset(dataval,0,20); //清除数据接收缓存区
flag = 0;
}
else if( strcmp( (const char *)dataval,(const char *)"ccc;" ) == 0 )
{
printf("zhiling3");
memset(dataval,0,20); //清除数据接收缓存区
flag = 0;
}
else
{
printf("no instructions !"); //识别到了结束符号但是未在定义内
memset(dataval,0,20); //清除数据接收缓存区
flag = 0;
}
}
}
3:运行结果
发送 指令 aaa;
发送指令 bbb;
发送指令ccc;
发送未定义的指令 结尾为结束符 ;
四:对接安信可 ESP_01SWIFI模块的AT指令处理
1:设置wifi模块的at指令
AT指令
1、AT+CWMODE=2 //设置为ap热点模式
2、AT+CWSAP="ESP8266_01","12345678",6,4 //开启热点 参数含义依次是:wifi名称、wifi密码、信道
//加密方式
3、AT+CIFSR //查询本地ip地址(外部设备连接网络后要进行数据的传输)
//的话需要进行IP地址、端口号来进行连接
4、AT+CIPMUX=1 //使能多连接,让多个设备连接网络
5、AT+CIPSERVER=1,8080 //开启服务端,端口号为8080
6、AT+CIPSEND=0,10 //发送长度为十个字节数据
7、AT //查询wifi模块是否能够正常工作
2: stm32通过串口给wifi模块发送指令让它工作在正确的模式
/****************************************
函数名 :esp_01s_init
作用 :初始化wifi模块 设置为ap热点模式 设置用户名密码 开启多连接
返回值 :无
参数 :无
****************************************/
void esp_01s_init(void)
{
HAL_Delay(5000); // wifi模块上电时会通过串口输出一段信息
//需要一点时间等待它结束输出信息
//延时时间为5s
//ap热点模式
printf("AT+CWMODE=2\r\n"); //全部程序中printf重定向了函数 这里用的是串口1
//at指令结束的结束符是回车所以需要最后末尾发送
// \r\n 用来完成指令的发送
HAL_Delay(300); //单位ms 延时
//设置wifi的用户和密码 在程序中用宏定义了用户名了名和密码
// 用户名:#define User_ESP01_SSID "ESP8266_01"
// 密码 : #define User_ESP01_PWD "1234567891"
printf("AT+CWSAP=\"%s\",\"%s\",6,4\r\n",User_ESP01_SSID,User_ESP01_PWD);
HAL_Delay(300); //ms
//开启多连接
printf("AT+CIPMUX=1\r\n");
HAL_Delay(300); //ms
//设置端口号
printf("AT+CIPSERVER=1,8080\r\n");
HAL_Delay(300); //ms
//在给wifi模块发送at指令时wifi模块会返回指令是正确还是错误所以其实在指令结束的
//最后进行数据接收区的清除
memset(dat,0,1024); //清除数据接收缓存区
}
3: 串口回调函数进行数据接收存放
/*********************************************************************
函数名:HAL_UART_RxCpltCallback
作用:串口回调函数,串口接收中断后进入这个函数
参数:无
返回值:无
无需调用这个函数,串口数据进行接收后会自动进入这个函数内
**********************************************************************/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
//接收到数据后,对数据进行处理
dataval[flag++] = ch; //将中断接收到的数据存放到数组中
//从数组0往后依次存放
//当要进行指令的接收处理时只需要遍历数组即可
//等待本次接受完毕重新启用串口中断接收
while(HAL_UART_Receive_IT(&huart1,&ch,1) != HAL_OK);
}
}
3:指令接收处理算法
//通过循环遍历数组中接受到的数据确定是否接受到指令并进行相应的处理
//这里可以简单一点判断结束符为 ; 当我们接收到数据且收到结束符时对数据接收区的数据进行
//识别以及处理进行相应的操作
for(uint16_t i=0;i<flag;i++)
{
if(dataval[i] == ';' ) //当接收到 结束符 ';'时进
{
if( strcmp( (const char *)dataval,(const char *)"aaa;" ) == 0 )
{
//识别指令到指令后进行相应的操作
//进行操作后清理数据缓存区
memset(dat,0,20); //清除数据接收缓存区
flag = 0;
}
else if(strcmp( (const char *)dataval,(const char *)"bbb;" ) == 0)
{
//识别指令到指令后进行相应的操作
//进行操作后清理数据缓存区
memset(dat,0,20); //清除数据接收缓存区
flag = 0;
}
else if(strcmp( (const char *)dataval,(const char *)"ccc;" )
{
//识别指令到指令后进行相应的操作
//进行操作后清理数据缓存区
memset(dat,0,20); //清除数据接收缓存区
flag = 0;
}
else
{
//进入这就说明出现了结束符 ;但是指令不匹配
memset(dat,0,20); //清除数据接收缓存区
flag = 0;
}
}
注意:需要包含相应的头文件
#include <stdio.h>
#include <string.h>