基于HAL库的stm32中串口的数据收发--基于串口命令shell实现(PC端通过usb转串口模块给单片机发指令,单片机接受指令并执行)以及对接安信可 ESP_01SWIFI模块的AT指令处理

一:任意字节串口接收实现

        (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>

                

内置 "cmd-list" 命令获取所有命令列表 支持 tab 键补全命令 支持 backspace 回退,这个在 putty 上有 bug ,还没修复。在secureCRT正常。 支持上下箭头回溯历史,这个功能没有做的很好; 支持左右箭头编辑当前命令行输入; 提供 shell_cmdparam()函数命令后所跟的数字参数(字符串整型),详见 demo 提供 shell_option_suport() 函数,使命令行支持 getopt()函数,详见 demo 系统共有9个文件,全部与硬件无关,编译语言要在 C99 以上(keil 在 project -> Options .. -> c/c++ -> C99 勾上) kernel.h // 一些必要的宏定义 shell.c,shell.h //具体的命令行解释的实现 ustdio.c,ustdio.h //非标准输出文件,重新链接 printf ,并提供一个小巧型的 printk 函数 avltree.c,avltree.h //平衡二叉树支持,shell 默认用链表建立查询机制,有必要可在shell.h 开启二叉树 getopt.c,getopt.h //网上找的 getopt() 源码 除了 getopt.c,getopt.h 两个文件是我从网上找的源码,主要实现命令行的 getopt()解析,其他的都是笔者所写。 使用: 1,首先把 shell.c ustdio.c 加入工程,这两个文件是必须的。 如果不用 getopt()函数可以不添加getopt.c文件。 shell默认使用链表来构建查询系统,但也提供了平衡二叉树的方式,在shell.h有开启的开关,如不需要可以不添加avltree.c。 include "shell.h" 2,先对硬件进行基本的初始化。 撰写串口送函数,形如 void usart_puts(char * str , uint16_t len) ; 调用函数 shell_init("shell >",usart_puts); //初始化shell的输入标志和默认输出指向 串口接收以包为单位。 3,新建全局变量 struct shell_input serial_shell ; 并初始化 SHELL_INPUT_INIT(&serial;_shell ,usart_puts);初始化输入缓存和输出交互; 4,串口接收到一整包函数后,调用 shell_input(&serial;_shell , packet , pktlen) ;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值