关于cubeIDE开发基本技巧及流程,本文不详细叙述,请参考:cubeIDE快速开发流程_py_free的博客-CSDN博客_cubeide汉化
一、stm32串口配置
本文采用的开发板是stm32L496VGT3,其有两个 USB 接口,一个为 USB ST-link 复用接口,作用为软件下载/调试/ 系统供电输入口。另一个为 USB OTG,用户可以外接 USB 设备,支持 1000mA,USB2.0 设备接入。本文就采用 USB ST-link口实现串口上下行通信及调试信息输出显示。
USB ST-Link(USB1) 接口的串口通信及调试信息需要我们映射实现。
打开cubeMX配置界面,配置串口映射,开启LPUART串口或其他USART*(1)的异步传输模式(2),配置串口参数(3),并将串口收发数据端口映射到PB10、PB11上(4),并开启中断功能(5),最后点击保存或生成代码按钮生成代码。
开启外部中断:
设置上拉输出:
二、串口驱动设计及代码实现
重新构建系统的printf函数,将其映射到LPUART串口。
【1】首先禁用CubeIDE生成syscall.c文件
【2】创建print.h和print.c两个驱动文件来取代syscall.c内的函数_read、_write等实现,本文是将这两个文件放置在ICore目录内
print.h内容如下:
- /*
- * print.h
- *
- * Created on: 2021年11月16日
- * Author: Administrator
- */
-
- #ifndef INC_RETARGET_H_
- #define INC_RETARGET_H_
-
- #include "stm32l4xx_hal.h"
- #include "stdio.h"//用于printf函数串口重映射
- #include <sys/stat.h>
-
- void ResetPrintInit(UART_HandleTypeDef *huart);//将printf()函数映射到指定串口上
-
- int _isatty(int fd);
- int _write(int fd, char* ptr, int len);
- int _close(int fd);
- int _lseek(int fd, int ptr, int dir);
- int _read(int fd, char* ptr, int len);
- int _fstat(int fd, struct stat* st);
-
- #endif /* INC_RETARGET_H_ */
复制代码
print.c内容如下,主要是将syscall.c内的空实现函数通过串口实现数据收发处理
- /*
- * print.c
- *
- * Created on: 2021年11月16日
- * Author: Administrator
- */
-
- #include <_ansi.h>
- #include <_syslist.h>
- #include <errno.h>
- #include <sys/time.h>
- #include <sys/times.h>
- #include <limits.h>
- #include <signal.h>
- #include <stdint.h>
- #include <stdio.h>
-
- #include "print.h"
-
- #if !defined(OS_USE_SEMIHOSTING)
- #define STDIN_FILENO 0
- #define STDOUT_FILENO 1
- #define STDERR_FILENO 2
-
- UART_HandleTypeDef *gHuart;
-
- void ResetPrintInit(UART_HandleTypeDef *huart) {
- gHuart = huart;
- /* Disable I/O buffering for STDOUT stream, so that
- * chars are sent out as soon as they are printed. */
- setvbuf(stdout, NULL, _IONBF, 0);
- }
- int _isatty(int fd) {
- if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
- return 1;
- errno = EBADF;
- return 0;
- }
- int _write(int fd, char* ptr, int len) {
- HAL_StatusTypeDef hstatus;
- if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
- //串口发送数据实现,可以main.c等功能代码中直接调用HAL_UART_Transmit也能实现串口发送数据
- hstatus = HAL_UART_Transmit(gHuart, (uint8_t *) ptr, len, HAL_MAX_DELAY);
- if (hstatus == HAL_OK)
- return len;
- else
- return EIO;
- }
- errno = EBADF;
- return -1;
- }
- int _close(int fd) {
- if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
- return 0;
- errno = EBADF;
- return -1;
- }
- int _lseek(int fd, int ptr, int dir) {
- (void) fd;
- (void) ptr;
- (void) dir;
- errno = EBADF;
- return -1;
- }
- int _read(int fd, char* ptr, int len) {
- HAL_StatusTypeDef hstatus;
- if (fd == STDIN_FILENO) {
- hstatus = HAL_UART_Receive(gHuart, (uint8_t *) ptr, 1, HAL_MAX_DELAY);
- if (hstatus == HAL_OK)
- return 1;
- else
- return EIO;
- }
- errno = EBADF;
- return -1;
- }
- int _fstat(int fd, struct stat* st) {
- if (fd >= STDIN_FILENO && fd <= STDERR_FILENO) {
- st->st_mode = S_IFCHR;
- return 0;
- }
- errno = EBADF;
- return 0;
- }
-
- #endif //#if !defined(OS_USE_SEMIHOSTING)
复制代码
【3】创建串口驱动接口,主要就是实现串口回调函数
前面print.h/c实现串口输出能力,但其输入能力由于lpusart开启了外部中断功能,还需我们实现其回调函数,因为cubeMX生成的HAL库(stm32l4xx_hal_uart.c,文件名因芯片不同有所区别)的串口接收回调函数是个弱声明函数,其实现源码没有做什么事。
现在创建usart.h、usart.c两个串口驱动文件,放置ICore目录下
usart.h内容如下,HAL_UART_RxCpltCallback会覆盖stm32l4xx_hal_uart.c的同名回调函数:
- /*
- * usart.h
- *
- * Created on: Oct 20, 2022
- * Author: Administrator
- */
-
- #ifndef INC_USART_H_
- #define INC_USART_H_
-
- #include "stm32l4xx_hal.h" //HAL库文件声明
- #include <string.h>//用于字符串处理的库
- #include "print.h"//用于printf函数串口重映射
-
- extern UART_HandleTypeDef hlpuart1;//声明USART1的HAL库结构体
-
- #define HLPUSART_REC_LEN 256//定义USART1最大接收字节数
-
- extern uint8_t HLPUSART_RX_BUF[HLPUSART_REC_LEN];//接收缓冲,最大HLPUSART_REC_LEN个字节.末字节为换行符
- extern uint16_t HLPUSART_RX_STA;//接收状态标记
- extern uint8_t HLPUSART_NewData;//当前串口中断接收的1个字节数据的缓存
-
-
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);//串口中断回调函数声明
-
- #endif /* INC_USART_H_ */
复制代码
usart.c内容如下:
- /*
- * usart.c
- *
- * Created on: Oct 20, 2022
- * Author: Administrator
- */
-
- #include "usart.h"
-
- uint8_t HLPUSART_RX_BUF[HLPUSART_REC_LEN];//接收缓冲,最大HLPUSART_REC_LEN个字节.末字节为换行符
- /*
- * bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000;
- * bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000;
- * bit13:预留
- * bit12:预留
- * bit11~0:接收到的有效字节数目(0~4095)
- */
- uint16_t HLPUSART_RX_STA=0;接收状态标记//bit15:接收完成标志,bit14:接收到回车(0x0d),bit13~0:接收到的有效字节数目
- uint8_t HLPUSART_NewData;//当前串口中断接收的1个字节数据的缓存
-
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//串口中断回调函数
- {
- if(huart ==&hlpuart1)//判断中断来源(串口1:USB转串口)
- {
- if(HLPUSART_RX_STA&0x4000){//溢出,重新开始
- HLPUSART_RX_STA=0;//接收错误,重新开始
- }
- if(HLPUSART_NewData==0x0d){//回车标记
- printf("getdata:%.*s \r\n", HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
- HLPUSART_RX_STA|=0x8000;//标记接到回车
- }else{
- if((HLPUSART_RX_STA&0X0FFF)<HLPUSART_REC_LEN){
- HLPUSART_RX_BUF[HLPUSART_RX_STA&0X0FFF]=HLPUSART_NewData; //将收到的数据放入数组
- HLPUSART_RX_STA++; //数据长度计数加1
- }else{
- HLPUSART_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
- }
- }
- HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData,1); //再开启接收中断
- }
- }
复制代码
三、串口驱动功能调用及编译实现
在原来的key.h/key.c中添加按键按下识别函数,
key.h:
- /*
- * key.h
- *
- * Created on: Sep 29, 2022
- * Author: py_hp
- */
-
- #ifndef KEY_H_
- #define KEY_H_
-
- #include "main.h"
- #include "gpio.h"
-
- GPIO_PinState get_key0_val();
- GPIO_PinState get_key1_val();
- GPIO_PinState get_key2_val();
-
- uint8_t KEY_0(void);
- uint8_t KEY_1(void);
- uint8_t KEY_2(void);
-
- #endif /* KEY_H_ */
复制代码
key.c内容如下:
- /*
- * key.c
- *
- * Created on: Sep 29, 2022
- * Author: py_hp
- */
- #include "key.h"
-
- GPIO_PinState get_key0_val()
- {
- return HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin);
- };
-
- GPIO_PinState get_key1_val()
- {
- return HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin);
- };
-
- GPIO_PinState get_key2_val()
- {
- return HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin);
- };
-
- uint8_t KEY_0(void)
- {
- uint8_t a;
- a=0;//如果未进入按键处理,则返回0
- if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET){//读按键接口的电平
- HAL_Delay(20);//延时去抖动
- if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
- a=1;//进入按键处理,返回1
- }
- }
- while(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET); //等待按键松开
- return a;
- }
-
- uint8_t KEY_1(void)
- {
- uint8_t a;
- a=0;//如果未进入按键处理,则返回0
- if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET){//读按键接口的电平
- HAL_Delay(20);//延时去抖动
- if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
- a=1;//进入按键处理,返回1
- }
- }
- while(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET); //等待按键松开
- return a;
- }
-
- uint8_t KEY_2(void)
- {
- uint8_t a;
- a=0;//如果未进入按键处理,则返回0
- if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET){//读按键接口的电平
- HAL_Delay(20);//延时去抖动
- if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
- a=1;//进入按键处理,返回1
- }
- }
- while(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET); //等待按键松开
- return a;
- }
-
复制代码
在main.c中调用串口驱动,其部分代码如下:
四、编译测试
编译及加载程序到开发板:
验证数据收发,按键1和按键2按下,顺利传输数据,输入“1”和“0”字段,可下行控制LED灯
————————————————
版权声明:py_free-物联智能
如有侵权请联系删除
|