一、usmart介绍
1、usmart简介
本USMART调试组件是正点原子开发提供的,主要功能是通过串口调试单片机里的函数,并执行。对于代码调试很有帮助。
我们普通的代码调试是通过:改写函数,修改参数,编译下载,查看结果;如果不满意的话继续这个流程。这样流程很麻烦而且单片机也是有寿命的,如此往复有损寿命。
使用USMART调试组件,只需要在串口调试助手里面输入函数以及参数,然后通过串口直接发送给单片机,就执行了一次参数调整,不满意的话可以在串口调试助手里面修改参数然后继续向单片机发送就可以了,直到满意为止。
例如我们调试lcd屏幕上显示的内容、位置、以及显示数字大小时,USMART组件的使用就可以让我们通过串口调试助手向单片机不断发送lcd屏幕的显示指令,我们可以不断调整文字的位置大小等等,直到符合预期,最后在代码中添加符合预期的代码参数就好了。而不用在代码中一次次的修改参数,编译,最后下载到单片机中查看结果。
2、usmart组件包含的文件以及介绍
usmart组件总共包含六个文件:如下图所示
(1)readme.txt是说明文件。
(2)usmart.c负责与外部交互;
usmart.h是头文件,其中有用户配置的宏定义,可以用来配置usmart的功能以及总参数 的长度(直接和SRAM占用挂钩)、是否使能定时器扫描、是否使用读写函数等。
(3)usmart_str.c负责命令和参数解析;usamrt_str.h是其头文件。
(4)usmart_config.c文件是用户用来添加一些需要用usmart管理的函数。
3、usamrt实现的流程
usmart组件的使用包含以下几个步骤:
(1)在usmart_config.c中添加我们需要调用的函数(在usmart_nametab数组中添加),只有添加了函数我们才能用usmart组件在串口调试助手中输入,调用这个函数的功能。
(2)初始化串口,串口初始完成才能通过对应串口向单片机发送调试函数命令。
(3)初始化usmart,通过usmart_init函数实现
(4)轮询usmart_scan函数,处理串口数据。
二、cubemx工程配置
cubemx工程配置,根据正点原子提供的usmart调试组件,对于usmart移植来讲,需要使用到串口1和定时器4,因此在cubemx中需要对串口1和定时器4进行初始化。
串口1是串口调试助手和单片机交互用的,需要配置串口的波特率,使能串口1中断等。如下图所示:
定时器4是用来实现定时扫描功能的,使能了定时器中断,并在中断中调用usmart_scan函数,以实现串口数据处理。
其中定时器4的初始化和中断服务函数放在了usmart.c,为了方便移植,我们直接用usmart.c中定义的定时器相关函数。因此,在这里我们需要随意定义和初始化一个定时器(在这里为定时器1),保证生成的“uvprojx”工程加载文件 "stm32f4xx_hal_tim.h",这样就可以保证在usmart.c文件中定义的“”TIM_HandleTypeDef”结构体时候不会报错,也即我们可以用库函数自己定义定时器4的的相关内容。
三、usmart相关文件的移植
cubemx初始化完成串口1和定时器1之后,我们就可以开始移植usmart文件了:
usmart文件夹直接复制黏贴到项目文件夹内,
然后在keil工程中,添加usmart文件夹中c文件,并在target中添加头文件路径。
由以上介绍可知,usmart中有六个文件,其中readme.txt为说明文件,剩余五个文件中,需要我们更改的是usmart.c、usmart.h、usmart_config.c。
(一)usmart.c文件修改
正点原子usmart.c文件包含三个头文件,其中usart.h为串口1头文件,sys.h为时钟初始化头文件,也包含了一些常用的数据类型短关键字(例如u32、u16、u8等)。
串口1和时钟初始化我们已经在cubemx中定义完成。其中生成的时钟初始化的代码放在了main.c中的SystemClock_Config()函数:
sys.h包含的一些常用的数据类型短关键字(例如u32、u16、u8等),我们可以将其放在其他的头文件中,例如延时函数头文件delay.h中,注意的是,如果需要使用这些数据类型短关键字,也需要包含delay.h。
所以,我们将数据类型短关键字的定义放到delay.h中,然后在usmart.c中就可以直接删除#include”sys.h“。
此外由于usmart.c中把定时器4的相关内容也包括进来了,需要添加:
#include "stm32f4xx_hal_tim.h"
才能使得定时器4的相关定义内容不报错。
此外在usmart.c文件中对定时器4的初始化需要根据情况修改:如中断优先级等,在这里我随便设置的,自己可以根据设置的优先级分组适当调整。
HAL_NVIC_SetPriority(TIM4_IRQn,0,0); //设置中断优先级,抢占优先级0,子优先级0
还有对于定时器中断的时间,定时器4的时钟频率来源于APB1,这里的sysclk为APB1的时钟频率,根据自己cubemx配置的时钟频率,来填写usmart_dev.init(sysclk)中的sysclk。
1 //sysclk:系统时钟(Mhz) 2 void usmart_init(u8 sysclk) 3 { 4 #if USMART_ENTIMX_SCAN==1 5 Timer4_Init(64535,(u32)sysclk*100-1);//分频,时钟为10K ,100ms中断一次,注意,计数频率必须为10Khz,以和runtime单位(0.1ms)同步. 6 #endif 7 usmart_dev.sptype=1; //十六进制显示参数 8 }
由于定时器是向上计数,最大值为65535,分频因子为sysclk*100-1,即为10khz,所需要达到100ms中断一次,需要计数1000次,65535-1000=64535为定时器自动重装值。
(二)cubemx生成的usart.c文件修改
cubemx生成的串口1初始化文件为usart.c,头文件为usart.h,在usmart.c中可以直接包含这个头文件。但是需要做出一些修改。
修改内容包括:添加支持printf()函数的代码、重写中断服务函数 USART1_IRQHandler(void) 、添加串口1中断回调函数 HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)。
1、首先为了支持printf()函数,需要在usart.c中添加如下代码:
#pragma import(__use_no_semihosting) struct __FILE { int handle; }; FILE __stdout; void _sys_exit(int x) { x = x; } int fputc(int ch, FILE *f) { HAL_UART_Transmit (&huart1 ,(uint8_t *)&ch,1,HAL_MAX_DELAY ); return ch; // while((USART1->SR&0X40)==0);// // USART1->DR = (uint8_t) ch; // return ch; }
2、重写中断服务函数USART1_IRQHandler(void)
我们使用正点原子提供的中断服务函数来接收数据,需要将cubemx生成的usart.c做一定的修改。
(1)首先usart.c中添加变量:
1 u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节. 2 u16 USART_RX_STA=0; //接收状态标记:bit15,接收完成标志;bit14:;接收到0x0d;bit13~0,接收到的有效字节数目 3 u8 aRxBuffer[RXBUFFERSIZE];//HAL库使用的串口接收缓冲
usart.h中添加定义:
1 #define USART_REC_LEN 200 //定义最大接收字节数 200 2 #define RXBUFFERSIZE 1 //缓存大小 3 4 extern u16 USART_RX_STA; //接收状态标记 5 extern u8 aRxBuffer[RXBUFFERSIZE];//HAL库USART接收Buffer 6 extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
cubemx生成的usart.c文件中已经定义了串口1的句柄为huart1:
1 UART_HandleTypeDef huart1;
而正点原子定义的句柄为UART1_Handler:
UART_HandleTypeDef UART1_Handler; //UART句柄
因此在cubemx生成的usart.c文件中,需要把UART1_Handler的定义删除,并把使用到UART1_Handler的地方替换为huart1
(2)其次添加中断服务函数
1 //串口1中断服务程序(其中使用到串口句柄的地方,已经更改为huart1) 2 void USART1_IRQHandler(void) 3 { 4 u32 timeout=0; 5 HAL_UART_IRQHandler(&huart1); //调用HAL库中断处理公用函数 6 7 timeout=0; 8 while (HAL_UART_GetState(&huart1) != HAL_UART_STATE_READY)//等待就绪 9 { 10 timeout++;////超时处理 11 if(timeout>HAL_MAX_DELAY) break; 12 13 } 14 15 timeout=0; 16 while(HAL_UART_Receive_IT(&huart1, (u8 *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1 17 { 18 timeout++; //超时处理 19 if(timeout>HAL_MAX_DELAY) break; 20 } 21 }
特别注意的是:cubemx配置完串口1并使能中断之后,也会生成中断服务函数,在stm32f4xx_it.c文件中:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
因为我们已经重写了中断服务函数,需要将这些代码全部注释掉。
(3)添加串口回调函数HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
1 //串口1回调函数 2 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 3 { 4 if(huart->Instance==USART1)//如果是串口1 5 { 6 if((USART_RX_STA&0x8000)==0)//接收未完成 7 { 8 if(USART_RX_STA&0x4000)//接收到了0x0d 9 { 10 if(aRxBuffer[0]!=0x0a)USART_RX_STA=0;//接收错误,重新开始 11 else USART_RX_STA|=0x8000; //接收完成了 12 } 13 else //还没收到0X0D 14 { 15 if(aRxBuffer[0]==0x0d)USART_RX_STA|=0x4000; 16 else 17 { 18 USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ; 19 USART_RX_STA++; 20 if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 21 } 22 } 23 } 24 25 } 26 }
(4)最后,需要开启串口1接收中断
在串口1的初始化完成之后开启接收中断 :HAL_UART_Receive_IT(&huart1, (u8 *)aRxBuffer, RXBUFFERSIZE);
void MX_USART1_UART_Init(void) { /* USER CODE BEGIN USART1_Init 0 */ /* USER CODE END USART1_Init 0 */ /* USER CODE BEGIN USART1_Init 1 */ /* USER CODE END USART1_Init 1 */ huart1.Instance = USART1; huart1.Init.BaudRate = 9600; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART1_Init 2 */ HAL_UART_Receive_IT(&huart1, (u8 *)aRxBuffer, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 /* USER CODE END USART1_Init 2 */ }
(三)usmart_config.c文件修改
在usamrt_config.c文件中添加要调试的函数,首先要包含该函数的头文件,其次按照如下所给代码的格式来添加对应的函数就好了:
1 (void*)LCD_Display_Dir,"void LCD_Display_Dir(u8 dir)", 2 (void*)LCD_ShowxNum,"void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode)",
(四)main.c文件修改
在main.c中添加头文件usmart.h,然后添加usmart组件初始化函数:
1 usmart_dev.init(84);
四、所有配置完成之后的文件
usmart.c
1 #include "usmart.h" 2 #include "usart.h" 3 #include "delay.h" 4 #include "stm32f4xx_hal_tim.h" 5 6 TIM_HandleTypeDef TIM4_Handler; //定时器句柄 7 //系统命令 8 u8 *sys_cmd_tab[]= 9 { 10 "?", 11 "help", 12 "list", 13 "id", 14 "hex", 15 "dec", 16 "runtime", 17 }; 18 //处理系统指令 19 //0,成功处理;其他,错误代码; 20 u8 usmart_sys_cmd_exe(u8 *str) 21 { 22 u8 i; 23 u8 sfname[MAX_FNAME_LEN];//存放本地函数名 24 u8 pnum; 25 u8 rval; 26 u32 res; 27 res=usmart_get_cmdname(str,sfname,&i,MAX_FNAME_LEN);//得到指令及指令长度 28 if(res)return USMART_FUNCERR;//错误的指令 29 str+=i; 30 for(i=0;i<sizeof(sys_cmd_tab)/4;i++)//支持的系统指令 31 { 32 if(usmart_strcmp(sfname,sys_cmd_tab[i])==0)break; 33 } 34 switch(i) 35 { 36 case 0: 37 case 1://帮助指令 38 printf("\r\n"); 39 #if USMART_USE_HELP 40 printf("------------------------USMART V3.3------------------------ \r\n"); 41 printf(" USMART是由ALIENTEK开发的一个灵巧的串口调试互交组件,通过 \r\n"); 42 printf("它,你可以通过串口助手调用程序里面的任何函数,并执行.因此,你可\r\n"); 43 printf("以随意更改函数的输入参数(支持数字(10/16进制,支持负数)、字符串\r\n"), 44 printf("、函数入口地址等作为参数),单个函数最多支持10个输入参数,并支持\r\n"), 45 printf("函数返回值显示.支持参数显示进制设置功能,支持进制转换功能.\r\n"); 46 printf("技术支持:www.openedv.com\r\n"); 47 printf("USMART有7个系统命令(必须小写):\r\n"); 48 printf("?: 获取帮助信息\r\n"); 49 printf("help: 获取帮助信息\r\n"); 50 printf("list: 可用的函数列表\r\n\n"); 51 printf("id: 可用函数的ID列表\r\n\n"); 52 printf("hex: 参数16进制显示,后跟空格+数字即执行进制转换\r\n\n"); 53 printf("dec: 参数10进制显示,后跟空格+数字即执行进制转换\r\n\n"); 54 printf("runtime:1,开启函数运行计时;0,关闭函数运行计时;\r\n\n"); 55 printf("请按照程序编写格式输入函数名及参数并以回车键结束.\r\n"); 56 printf("--------------------------ALIENTEK------------------------- \r\n"); 57 #else 58 printf("指令失效\r\n"); 59 #endif 60 break; 61 case 2://查询指令 62 printf("\r\n"); 63 printf("-------------------------函数清单--------------------------- \r\n"); 64 for(i=0;i<usmart_dev.fnum;i++)printf("%s\r\n",usmart_dev.funs[i].name); 65 printf("\r\n"); 66 break; 67 case 3://查询ID 68 printf("\r\n"); 69 printf("-------------------------函数 ID --------------------------- \r\n"); 70 for(i=0;i<usmart_dev.fnum;i++) 71 { 72 usmart_get_fname((u8*)usmart_dev.funs[i].name,sfname,&pnum,&rval);//得到本地函数名 73 printf("%s id is:\r\n0X%08X\r\n",sfname,usmart_dev.funs[i].func); //显示ID 74 } 75 printf("\r\n"); 76 break; 77 case 4://hex指令 78 printf("\r\n"); 79 usmart_get_aparm(str,sfname,&i); 80 if(i==0)//参数正常 81 { 82 i=usmart_str2num(sfname,&res); //记录该参数 83 if(i==0) //进制转换功能 84 { 85 printf("HEX:0X%X\r\n",res); //转为16进制 86 }else if(i!=4)return USMART_PARMERR;//参数错误. 87 else //参数显示设定功能 88 { 89 printf("16进制参数显示!\r\n"); 90 usmart_dev.sptype=SP_TYPE_HEX; 91 } 92 93 }else return USMART_PARMERR; //参数错误. 94 printf("\r\n"); 95 break; 96 case 5://dec指令 97 printf("\r\n"); 98 usmart_get_aparm(str,sfname,&i); 99 if(i==0)//参数正常 100 { 101 i=usmart_str2num(sfname,&res); //记录该参数 102 if(i==0) //进制转换功能 103 { 104 printf("DEC:%lu\r\n",res); //转为10进制 105 }else if(i!=4)return USMART_PARMERR;//参数错误. 106 else //参数显示设定功能 107 { 108 printf("10进制参数显示!\r\n"); 109 usmart_dev.sptype=SP_TYPE_DEC; 110 } 111 112 }else return USMART_PARMERR; //参数错误. 113 printf("\r\n"); 114 break; 115 case 6://runtime指令,设置是否显示函数执行时间 116 printf("\r\n"); 117 usmart_get_aparm(str,sfname,&i); 118 if(i==0)//参数正常 119 { 120 i=usmart_str2num(sfname,&res); //记录该参数 121 if(i==0) //读取指定地址数据功能 122 { 123 if(USMART_ENTIMX_SCAN==0)printf("\r\nError! \r\nTo EN RunTime function,Please set USMART_ENTIMX_SCAN = 1 first!\r\n");//报错 124 else 125 { 126 usmart_dev.runtimeflag=res; 127 if(usmart_dev.runtimeflag)printf("Run Time Calculation ON\r\n"); 128 else printf("Run Time Calculation OFF\r\n"); 129 } 130 }else return USMART_PARMERR; //未带参数,或者参数错误 131 }else return USMART_PARMERR; //参数错误. 132 printf("\r\n"); 133 break; 134 default://非法指令 135 return USMART_FUNCERR; 136 } 137 return 0; 138 } 139 //////////////////////////////////////////////////////////////////////////////////////// 140 //移植注意:本例是以stm32为例,如果要移植到其他mcu,请做相应修改. 141 //usmart_reset_runtime,清除函数运行时间,连同定时器的计数寄存器以及标志位一起清零.并设置重装载值为最大,以最大限度的延长计时时间. 142 //usmart_get_runtime,获取函数运行时间,通过读取CNT值获取,由于usmart是通过中断调用的函数,所以定时器中断不再有效,此时最大限度 143 //只能统计2次CNT的值,也就是清零后+溢出一次,当溢出超过2次,没法处理,所以最大延时,控制在:2*计数器CNT*0.1ms.对STM32来说,是:13.1s左右 144 //其他的:TIM4_IRQHandler和Timer4_Init,需要根据MCU特点自行修改.确保计数器计数频率为:10Khz即可.另外,定时器不要开启自动重装载功能!! 145 146 #if USMART_ENTIMX_SCAN==1 147 //复位runtime 148 //需要根据所移植到的MCU的定时器参数进行修改 149 void usmart_reset_runtime(void) 150 { 151 __HAL_TIM_CLEAR_FLAG(&TIM4_Handler,TIM_FLAG_UPDATE);//清除中断标志位 152 __HAL_TIM_SET_AUTORELOAD(&TIM4_Handler,0XFFFF); //将重装载值设置到最大 153 __HAL_TIM_SET_COUNTER(&TIM4_Handler,0); //清空定时器的CNT 154 usmart_dev.runtime=0; 155 } 156 //获得runtime时间 157 //返回值:执行时间,单位:0.1ms,最大延时时间为定时器CNT值的2倍*0.1ms 158 //需要根据所移植到的MCU的定时器参数进行修改 159 u32 usmart_get_runtime(void) 160 { 161 if(__HAL_TIM_GET_FLAG(&TIM4_Handler,TIM_FLAG_UPDATE)==SET)//在运行期间,产生了定时器溢出 162 { 163 usmart_dev.runtime+=0XFFFF; 164 } 165 usmart_dev.runtime+=__HAL_TIM_GET_COUNTER(&TIM4_Handler); 166 return usmart_dev.runtime; //返回计数值 167 } 168 //下面这两个函数,非USMART函数,放到这里,仅仅方便移植. 169 //定时器4中断服务程序 170 void TIM4_IRQHandler(void) 171 { 172 if(__HAL_TIM_GET_IT_SOURCE(&TIM4_Handler,TIM_IT_UPDATE)==SET)//溢出中断 173 { 174 usmart_dev.scan(); //执行usmart扫描 175 __HAL_TIM_SET_COUNTER(&TIM4_Handler,0);; //清空定时器的CNT 176 __HAL_TIM_SET_AUTORELOAD(&TIM4_Handler,100);//恢复原来的设置 177 } 178 __HAL_TIM_CLEAR_IT(&TIM4_Handler, TIM_IT_UPDATE);//清除中断标志位 179 } 180 181 //使能定时器4,使能中断. 182 void Timer4_Init(u16 arr,u16 psc) 183 { 184 //定时器4 185 __HAL_RCC_TIM4_CLK_ENABLE(); 186 HAL_NVIC_SetPriority(TIM4_IRQn,0,0); //设置中断优先级,抢占优先级0,子优先级0 187 HAL_NVIC_EnableIRQ(TIM4_IRQn); //开启ITM4中断 188 189 TIM4_Handler.Instance=TIM4; //通用定时器4 190 TIM4_Handler.Init.Prescaler=psc; //分频 191 TIM4_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数器 192 TIM4_Handler.Init.Period=arr; //自动装载值 193 TIM4_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; 194 HAL_TIM_Base_Init(&TIM4_Handler); 195 HAL_TIM_Base_Start_IT(&TIM4_Handler); //使能定时器4和定时器4中断 196 } 197 198 199 #endif 200 //////////////////////////////////////////////////////////////////////////////////////// 201 //初始化串口控制器 202 //sysclk:系统时钟(Mhz) 203 void usmart_init(u8 sysclk) 204 { 205 #if USMART_ENTIMX_SCAN==1 206 Timer4_Init(64535,(u32)sysclk*100-1);//分频,时钟为10K ,100ms中断一次,注意,计数频率必须为10Khz,以和runtime单位(0.1ms)同步. 207 #endif 208 usmart_dev.sptype=1; //十六进制显示参数 209 } 210 //从str中获取函数名,id,及参数信息 211 //*str:字符串指针. 212 //返回值:0,识别成功;其他,错误代码. 213 u8 usmart_cmd_rec(u8*str) 214 { 215 u8 sta,i,rval;//状态 216 u8 rpnum,spnum; 217 u8 rfname[MAX_FNAME_LEN];//暂存空间,用于存放接收到的函数名 218 u8 sfname[MAX_FNAME_LEN];//存放本地函数名 219 sta=usmart_get_fname(str,rfname,&rpnum,&rval);//得到接收到的数据的函数名及参数个数 220 if(sta)return sta;//错误 221 for(i=0;i<usmart_dev.fnum;i++) 222 { 223 sta=usmart_get_fname((u8*)usmart_dev.funs[i].name,sfname,&spnum,&rval);//得到本地函数名及参数个数 224 if(sta)return sta;//本地解析有误 225 if(usmart_strcmp(sfname,rfname)==0)//相等 226 { 227 if(spnum>rpnum)return USMART_PARMERR;//参数错误(输入参数比源函数参数少) 228 usmart_dev.id=i;//记录函数ID. 229 break;//跳出. 230 } 231 } 232 if(i==usmart_dev.fnum)return USMART_NOFUNCFIND; //未找到匹配的函数 233 sta=usmart_get_fparam(str,&i); //得到函数参数个数 234 if(sta)return sta; //返回错误 235 usmart_dev.pnum=i; //参数个数记录 236 return USMART_OK; 237 } 238 //usamrt执行函数 239 //该函数用于最终执行从串口收到的有效函数. 240 //最多支持10个参数的函数,更多的参数支持也很容易实现.不过用的很少.一般5个左右的参数的函数已经很少见了. 241 //该函数会在串口打印执行情况.以:"函数名(参数1,参数2...参数N)=返回值".的形式打印. 242 //当所执行的函数没有返回值的时候,所打印的返回值是一个无意义的数据. 243 void usmart_exe(void) 244 { 245 u8 id,i; 246 u32 res; 247 u32 temp[MAX_PARM];//参数转换,使之支持了字符串 248 u8 sfname[MAX_FNAME_LEN];//存放本地函数名 249 u8 pnum,rval; 250 id=usmart_dev.id; 251 if(id>=usmart_dev.fnum)return;//不执行. 252 usmart_get_fname((u8*)usmart_dev.funs[id].name,sfname,&pnum,&rval);//得到本地函数名,及参数个数 253 printf("\r\n%s(",sfname);//输出正要执行的函数名 254 for(i=0;i<pnum;i++)//输出参数 255 { 256 if(usmart_dev.parmtype&(1<<i))//参数是字符串 257 { 258 printf("%c",'"'); 259 printf("%s",usmart_dev.parm+usmart_get_parmpos(i)); 260 printf("%c",'"'); 261 temp[i]=(u32)&(usmart_dev.parm[usmart_get_parmpos(i)]); 262 }else //参数是数字 263 { 264 temp[i]=*(u32*)(usmart_dev.parm+usmart_get_parmpos(i)); 265 if(usmart_dev.sptype==SP_TYPE_DEC)printf("%ld",temp[i]);//10进制参数显示 266 else printf("0X%X",temp[i]);//16进制参数显示 267 } 268 if(i!=pnum-1)printf(","); 269 } 270 printf(")"); 271 #if USMART_ENTIMX_SCAN==1 272 usmart_reset_runtime(); //计时器清零,开始计时 273 #endif 274 switch(usmart_dev.pnum) 275 { 276 case 0://无参数(void类型) 277 res=(*(u32(*)())usmart_dev.funs[id].func)(); 278 break; 279 case 1://有1个参数 280 res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0]); 281 break; 282 case 2://有2个参数 283 res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1]); 284 break; 285 case 3://有3个参数 286 res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2]); 287 break; 288 case 4://有4个参数 289 res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3]); 290 break; 291 case 5://有5个参数 292 res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4]); 293 break; 294 case 6://有6个参数 295 res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4],\ 296 temp[5]); 297 break; 298 case 7://有7个参数 299 res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4],\ 300 temp[5],temp[6]); 301 break; 302 case 8://有8个参数 303 res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4],\ 304 temp[5],temp[6],temp[7]); 305 break; 306 case 9://有9个参数 307 res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4],\ 308 temp[5],temp[6],temp[7],temp[8]); 309 break; 310 case 10://有10个参数 311 res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4],\ 312 temp[5],temp[6],temp[7],temp[8],temp[9]); 313 break; 314 } 315 #if USMART_ENTIMX_SCAN==1 316 usmart_get_runtime();//获取函数执行时间 317 #endif 318 if(rval==1)//需要返回值. 319 { 320 if(usmart_dev.sptype==SP_TYPE_DEC)printf("=%lu;\r\n",res);//输出执行结果(10进制参数显示) 321 else printf("=0X%X;\r\n",res);//输出执行结果(16进制参数显示) 322 }else printf(";\r\n"); //不需要返回值,直接输出结束 323 if(usmart_dev.runtimeflag) //需要显示函数执行时间 324 { 325 printf("Function Run Time:%d.%1dms\r\n",usmart_dev.runtime/10,usmart_dev.runtime%10);//打印函数执行时间 326 } 327 } 328 //usmart扫描函数 329 //通过调用该函数,实现usmart的各个控制.该函数需要每隔一定时间被调用一次 330 //以及时执行从串口发过来的各个函数. 331 //本函数可以在中断里面调用,从而实现自动管理. 332 //如果非ALIENTEK用户,则USART_RX_STA和USART_RX_BUF[]需要用户自己实现 333 void usmart_scan(void) 334 { 335 u8 sta,len; 336 if(USART_RX_STA&0x8000)//串口接收完成? 337 { 338 len=USART_RX_STA&0x3fff; //得到此次接收到的数据长度 339 USART_RX_BUF[len]='\0'; //在末尾加入结束符. 340 sta=usmart_dev.cmd_rec(USART_RX_BUF);//得到函数各个信息 341 if(sta==0)usmart_dev.exe(); //执行函数 342 else 343 { 344 len=usmart_sys_cmd_exe(USART_RX_BUF); 345 if(len!=USMART_FUNCERR)sta=len; 346 if(sta) 347 { 348 switch(sta) 349 { 350 case USMART_FUNCERR: 351 printf("函数错误!\r\n"); 352 353 break; 354 case USMART_PARMERR: 355 printf("参数错误!\r\n"); 356 break; 357 case USMART_PARMOVER: 358 printf("参数太多!\r\n"); 359 break; 360 case USMART_NOFUNCFIND: 361 printf("未找到匹配的函数!\r\n"); 362 break; 363 } 364 } 365 } 366 USART_RX_STA=0;//状态寄存器清空 367 } 368 } 369 #if USMART_USE_WRFUNS==1 //如果使能了读写操作 370 //读取指定地址的值 371 u32 read_addr(u32 addr) 372 { 373 return *(u32*)addr;// 374 } 375 //在指定地址写入指定的值 376 void write_addr(u32 addr,u32 val) 377 { 378 *(u32*)addr=val; 379 } 380 #endif
usart.c(我使用到了三个串口,大家只需看串口1定义的内容即可)
1 /* USER CODE BEGIN Header */ 2 /** 3 ****************************************************************************** 4 * @file usart.c 5 * @brief This file provides code for the configuration 6 * of the USART instances. 7 ****************************************************************************** 8 * @attention 9 * 10 * Copyright (c) 2023 STMicroelectronics. 11 * All rights reserved. 12 * 13 * This software is licensed under terms that can be found in the LICENSE file 14 * in the root directory of this software component. 15 * If no LICENSE file comes with this software, it is provided AS-IS. 16 * 17 ****************************************************************************** 18 */ 19 #include <stdio.h> 20 #include <stdarg.h> 21 #include <string.h> 22 23 /* USER CODE END Header */ 24 /* Includes ------------------------------------------------------------------*/ 25 #include "usart.h" 26 /* USER CODE BEGIN 0 */ 27 /**********************************begin************************************************************/ 28 29 #pragma import(__use_no_semihosting) 30 31 struct __FILE 32 { 33 int handle; 34 35 }; 36 37 FILE __stdout; 38 39 void _sys_exit(int x) 40 { 41 x = x; 42 } 43 44 int fputc(int ch, FILE *f) 45 { 46 47 HAL_UART_Transmit (&huart1 ,(uint8_t *)&ch,1,HAL_MAX_DELAY ); 48 return ch; 49 50 // while((USART1->SR&0X40)==0);// 51 // USART1->DR = (uint8_t) ch; 52 // return ch; 53 } 54 /**********************************end************************************************************/ 55 56 /**********************************serial port transmit function begin****************************************************/ 57 /** 58 59 */ 60 61 void UsartPrintf(UART_HandleTypeDef USARTx, char *fmt,...) 62 { 63 64 unsigned char UsartPrintfBuf[256]; 65 va_list ap; 66 unsigned char *pStr = UsartPrintfBuf; 67 68 va_start(ap, fmt); 69 vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap); // 70 va_end(ap); 71 72 while(*pStr != NULL) 73 { 74 HAL_UART_Transmit (&USARTx ,(uint8_t *)pStr++,1,HAL_MAX_DELAY ); 75 } 76 77 } 78 /**********************************serial port transmit function end****************************************************/ 79 80 //串口1中断服务程序 81 //注意,读取USARTx->SR能避免莫名其妙的错误 82 u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节. 83 //接收状态标记:bit15,接收完成标志;bit14:;接收到0x0d;bit13~0,接收到的有效字节数目 84 u16 USART_RX_STA=0; //接收状态标记 85 u8 aRxBuffer[RXBUFFERSIZE];//HAL库使用的串口接收缓冲 86 87 /* USER CODE END 0 */ 88 89 UART_HandleTypeDef huart1; 90 UART_HandleTypeDef huart2; 91 UART_HandleTypeDef huart3; 92 93 /* USART1 init function */ 94 95 void MX_USART1_UART_Init(void) 96 { 97 98 /* USER CODE BEGIN USART1_Init 0 */ 99 100 /* USER CODE END USART1_Init 0 */ 101 102 /* USER CODE BEGIN USART1_Init 1 */ 103 104 /* USER CODE END USART1_Init 1 */ 105 huart1.Instance = USART1; 106 huart1.Init.BaudRate = 9600; 107 huart1.Init.WordLength = UART_WORDLENGTH_8B; 108 huart1.Init.StopBits = UART_STOPBITS_1; 109 huart1.Init.Parity = UART_PARITY_NONE; 110 huart1.Init.Mode = UART_MODE_TX_RX; 111 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; 112 huart1.Init.OverSampling = UART_OVERSAMPLING_16; 113 if (HAL_UART_Init(&huart1) != HAL_OK) 114 { 115 Error_Handler(); 116 } 117 /* USER CODE BEGIN USART1_Init 2 */ 118 HAL_UART_Receive_IT(&huart1, (u8 *)aRxBuffer, RXBUFFERSIZE); 119 //该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 120 /* USER CODE END USART1_Init 2 */ 121 122 } 123 /* USART2 init function */ 124 125 void MX_USART2_UART_Init(void) 126 { 127 128 /* USER CODE BEGIN USART2_Init 0 */ 129 130 /* USER CODE END USART2_Init 0 */ 131 132 /* USER CODE BEGIN USART2_Init 1 */ 133 134 /* USER CODE END USART2_Init 1 */ 135 huart2.Instance = USART2; 136 huart2.Init.BaudRate = 9600; 137 huart2.Init.WordLength = UART_WORDLENGTH_8B; 138 huart2.Init.StopBits = UART_STOPBITS_1; 139 huart2.Init.Parity = UART_PARITY_NONE; 140 huart2.Init.Mode = UART_MODE_TX_RX; 141 huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; 142 huart2.Init.OverSampling = UART_OVERSAMPLING_16; 143 if (HAL_UART_Init(&huart2) != HAL_OK) 144 { 145 Error_Handler(); 146 } 147 /* USER CODE BEGIN USART2_Init 2 */ 148 149 /* USER CODE END USART2_Init 2 */ 150 151 } 152 /* USART3 init function */ 153 154 void MX_USART3_UART_Init(void) 155 { 156 157 /* USER CODE BEGIN USART3_Init 0 */ 158 159 /* USER CODE END USART3_Init 0 */ 160 161 /* USER CODE BEGIN USART3_Init 1 */ 162 163 /* USER CODE END USART3_Init 1 */ 164 huart3.Instance = USART3; 165 huart3.Init.BaudRate = 9600; 166 huart3.Init.WordLength = UART_WORDLENGTH_8B; 167 huart3.Init.StopBits = UART_STOPBITS_1; 168 huart3.Init.Parity = UART_PARITY_NONE; 169 huart3.Init.Mode = UART_MODE_TX_RX; 170 huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; 171 huart3.Init.OverSampling = UART_OVERSAMPLING_16; 172 if (HAL_UART_Init(&huart3) != HAL_OK) 173 { 174 Error_Handler(); 175 } 176 /* USER CODE BEGIN USART3_Init 2 */ 177 178 /* USER CODE END USART3_Init 2 */ 179 180 } 181 182 void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) 183 { 184 185 GPIO_InitTypeDef GPIO_InitStruct = {0}; 186 if(uartHandle->Instance==USART1) 187 { 188 /* USER CODE BEGIN USART1_MspInit 0 */ 189 190 /* USER CODE END USART1_MspInit 0 */ 191 /* USART1 clock enable */ 192 __HAL_RCC_USART1_CLK_ENABLE(); 193 194 __HAL_RCC_GPIOA_CLK_ENABLE(); 195 /**USART1 GPIO Configuration 196 PA9 ------> USART1_TX 197 PA10 ------> USART1_RX 198 */ 199 GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; 200 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 201 GPIO_InitStruct.Pull = GPIO_NOPULL; 202 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 203 GPIO_InitStruct.Alternate = GPIO_AF7_USART1; 204 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 205 206 /* USART1 interrupt Init */ 207 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); 208 HAL_NVIC_EnableIRQ(USART1_IRQn); 209 /* USER CODE BEGIN USART1_MspInit 1 */ 210 211 /* USER CODE END USART1_MspInit 1 */ 212 } 213 else if(uartHandle->Instance==USART2) 214 { 215 /* USER CODE BEGIN USART2_MspInit 0 */ 216 217 /* USER CODE END USART2_MspInit 0 */ 218 /* USART2 clock enable */ 219 __HAL_RCC_USART2_CLK_ENABLE(); 220 221 __HAL_RCC_GPIOA_CLK_ENABLE(); 222 /**USART2 GPIO Configuration 223 PA2 ------> USART2_TX 224 PA3 ------> USART2_RX 225 */ 226 GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3; 227 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 228 GPIO_InitStruct.Pull = GPIO_NOPULL; 229 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 230 GPIO_InitStruct.Alternate = GPIO_AF7_USART2; 231 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 232 233 /* USART2 interrupt Init */ 234 HAL_NVIC_SetPriority(USART2_IRQn, 2, 0); 235 HAL_NVIC_EnableIRQ(USART2_IRQn); 236 /* USER CODE BEGIN USART2_MspInit 1 */ 237 238 /* USER CODE END USART2_MspInit 1 */ 239 } 240 else if(uartHandle->Instance==USART3) 241 { 242 /* USER CODE BEGIN USART3_MspInit 0 */ 243 244 /* USER CODE END USART3_MspInit 0 */ 245 /* USART3 clock enable */ 246 __HAL_RCC_USART3_CLK_ENABLE(); 247 248 __HAL_RCC_GPIOB_CLK_ENABLE(); 249 /**USART3 GPIO Configuration 250 PB10 ------> USART3_TX 251 PB11 ------> USART3_RX 252 */ 253 GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11; 254 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 255 GPIO_InitStruct.Pull = GPIO_NOPULL; 256 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 257 GPIO_InitStruct.Alternate = GPIO_AF7_USART3; 258 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 259 260 /* USART3 interrupt Init */ 261 HAL_NVIC_SetPriority(USART3_IRQn, 3, 0); 262 HAL_NVIC_EnableIRQ(USART3_IRQn); 263 /* USER CODE BEGIN USART3_MspInit 1 */ 264 265 /* USER CODE END USART3_MspInit 1 */ 266 } 267 } 268 269 void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) 270 { 271 272 if(uartHandle->Instance==USART1) 273 { 274 /* USER CODE BEGIN USART1_MspDeInit 0 */ 275 276 /* USER CODE END USART1_MspDeInit 0 */ 277 /* Peripheral clock disable */ 278 __HAL_RCC_USART1_CLK_DISABLE(); 279 280 /**USART1 GPIO Configuration 281 PA9 ------> USART1_TX 282 PA10 ------> USART1_RX 283 */ 284 HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10); 285 286 /* USART1 interrupt Deinit */ 287 HAL_NVIC_DisableIRQ(USART1_IRQn); 288 /* USER CODE BEGIN USART1_MspDeInit 1 */ 289 290 /* USER CODE END USART1_MspDeInit 1 */ 291 } 292 else if(uartHandle->Instance==USART2) 293 { 294 /* USER CODE BEGIN USART2_MspDeInit 0 */ 295 296 /* USER CODE END USART2_MspDeInit 0 */ 297 /* Peripheral clock disable */ 298 __HAL_RCC_USART2_CLK_DISABLE(); 299 300 /**USART2 GPIO Configuration 301 PA2 ------> USART2_TX 302 PA3 ------> USART2_RX 303 */ 304 HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3); 305 306 /* USART2 interrupt Deinit */ 307 HAL_NVIC_DisableIRQ(USART2_IRQn); 308 /* USER CODE BEGIN USART2_MspDeInit 1 */ 309 310 /* USER CODE END USART2_MspDeInit 1 */ 311 } 312 else if(uartHandle->Instance==USART3) 313 { 314 /* USER CODE BEGIN USART3_MspDeInit 0 */ 315 316 /* USER CODE END USART3_MspDeInit 0 */ 317 /* Peripheral clock disable */ 318 __HAL_RCC_USART3_CLK_DISABLE(); 319 320 /**USART3 GPIO Configuration 321 PB10 ------> USART3_TX 322 PB11 ------> USART3_RX 323 */ 324 HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11); 325 326 /* USART3 interrupt Deinit */ 327 HAL_NVIC_DisableIRQ(USART3_IRQn); 328 /* USER CODE BEGIN USART3_MspDeInit 1 */ 329 330 /* USER CODE END USART3_MspDeInit 1 */ 331 } 332 } 333 334 /* USER CODE BEGIN 1 */ 335 336 //串口1中断服务程序 337 void USART1_IRQHandler(void) 338 { 339 u32 timeout=0; 340 HAL_UART_IRQHandler(&huart1); //调用HAL库中断处理公用函数 341 342 timeout=0; 343 while (HAL_UART_GetState(&huart1) != HAL_UART_STATE_READY)//等待就绪 344 { 345 timeout++;////超时处理 346 if(timeout>HAL_MAX_DELAY) break; 347 348 } 349 350 timeout=0; 351 while(HAL_UART_Receive_IT(&huart1, (u8 *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1 352 { 353 timeout++; //超时处理 354 if(timeout>HAL_MAX_DELAY) break; 355 } 356 } 357 358 //串口1回调函数 359 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 360 { 361 if(huart->Instance==USART1)//如果是串口1 362 { 363 if((USART_RX_STA&0x8000)==0)//接收未完成 364 { 365 if(USART_RX_STA&0x4000)//接收到了0x0d 366 { 367 if(aRxBuffer[0]!=0x0a)USART_RX_STA=0;//接收错误,重新开始 368 else USART_RX_STA|=0x8000; //接收完成了 369 } 370 else //还没收到0X0D 371 { 372 if(aRxBuffer[0]==0x0d)USART_RX_STA|=0x4000; 373 else 374 { 375 USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ; 376 USART_RX_STA++; 377 if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 378 } 379 } 380 } 381 382 } 383 } 384 385 /* USER CODE END 1 */
usart.h
1 #ifndef __USART_H__ 2 #define __USART_H__ 3 4 #ifdef __cplusplus 5 extern "C" { 6 #endif 7 8 /* Includes ------------------------------------------------------------------*/ 9 #include "main.h" 10 11 /* USER CODE BEGIN Includes */ 12 #include "delay.h" 13 /* USER CODE END Includes */ 14 15 extern UART_HandleTypeDef huart1; 16 extern UART_HandleTypeDef huart2; 17 extern UART_HandleTypeDef huart3; 18 19 /* USER CODE BEGIN Private defines */ 20 #define usart_debug huart1 // 21 #define usart_sensor huart2 // 22 #define usart_wifi huart3 // 23 #define USART_REC_LEN 200 //定义最大接收字节数 200 24 #define RXBUFFERSIZE 1 //缓存大小 25 26 extern u16 USART_RX_STA; //接收状态标记 27 extern u8 aRxBuffer[RXBUFFERSIZE];//HAL库USART接收Buffer 28 extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 29 /* USER CODE END Private defines */ 30 31 void MX_USART1_UART_Init(void); 32 void MX_USART2_UART_Init(void); 33 void MX_USART3_UART_Init(void); 34 35 /* USER CODE BEGIN Prototypes */ 36 void UsartPrintf(UART_HandleTypeDef USARTx,char *fmt,...); 37 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); 38 /* USER CODE END Prototypes */ 39 40 #ifdef __cplusplus 41 } 42 #endif 43 44 #endif /* __USART_H__ */
delay.h
1 #ifndef _DELAY_H 2 #define _DELAY_H 3 #include "stm32f4xx.h" 4 typedef int32_t s32; 5 typedef int16_t s16; 6 typedef int8_t s8; 7 8 typedef const int32_t sc32; 9 typedef const int16_t sc16; 10 typedef const int8_t sc8; 11 12 typedef __IO int32_t vs32; 13 typedef __IO int16_t vs16; 14 typedef __IO int8_t vs8; 15 16 typedef __I int32_t vsc32; 17 typedef __I int16_t vsc16; 18 typedef __I int8_t vsc8; 19 20 typedef uint32_t u32; 21 typedef uint16_t u16; 22 typedef uint8_t u8; 23 24 typedef const uint32_t uc32; 25 typedef const uint16_t uc16; 26 typedef const uint8_t uc8; 27 28 typedef __IO uint32_t vu32; 29 typedef __IO uint16_t vu16; 30 typedef __IO uint8_t vu8; 31 32 typedef __I uint32_t vuc32; 33 typedef __I uint16_t vuc16; 34 typedef __I uint8_t vuc8; 35 36 void delay_init(u8 SYSCLK); 37 void delay_ms(u16 nms); 38 void delay_us(u32 nus); 39 40 #endif
如有问题可评论沟通。整理不易,如有帮助请点赞收藏~