赞
踩
串口理论部分可看51部分:链接
数据帧 = 帧头(2字节,例如AA、BB) + 数据长度(2字节)+ 数据 + CRC16校验(2字节) + 帧尾(2字节)
串口一发送命令控制LED灯(PB5、PE5)
LED灯配置请看:链接
串口配置:
配置中断NVIC(嵌套向量中断控制器)
配置DMA:
Cube IDE中串口打印浮点数据配置方法(参考):进入“Project→Properties”;显示界面如下。按照图片中的设置完成即可!
串口重定向配置:
uint8_t u_buf[256]; //usart.c,24行
#include <stdio.h> //usart.h,32行
extern uint8_t u_buf[256]; //usart.h,38行
#define printf(...) HAL_UART_Transmit(&huart1, (uint8_t *)u_buf, sprintf((char*)u_buf, __VA_ARGS__), 0xffff) //usart.h,39行
缺点:
必须要等待数据发送完或者等待时间超时,代码才会往下走
必须要等待数据接收到固定的字节长度,超时,代码才往下走
mian.c
/* USER CODE BEGIN Includes */ #include <string.h> //26行 #include <stdio.h> //27 /* USER CODE END Includes */ /* USER CODE BEGIN PV */ uint8_t UART_Recv[5]; //48行 char UART_Str[30]; //49行 /* USER CODE END PV */ //参数1:UART 模块的配置信息的指针,参数2:数据缓冲区的指针,参数3:接收字节长度,参数4:接收超时时间(单位为毫秒) HAL_UART_Receive(&huart1, UART_Recv, 4, 1000); //接收数据函数 if(strcmp("LED1", (char *)UART_Recv) == 0) //字符串比较函数 { HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); memset(UART_Recv,'\0',5); //替换字符函数,常用于清除指定空间 } if(!strcmp("LED2", (char *)UART_Recv)) //字符串比较函数 { HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin); memset(UART_Recv,'\0',5); } sprintf(UART_Str, "%f\n", 666.6); //参数1:UART 模块的配置信息的指针,参数2:发送的字符串或字符数组,参数3:发送字节长度,参数4:接收超时时间(单位为毫秒) HAL_UART_Transmit(&huart1, (char *)UART_Str, strlen(UART_Str), 1000); //发送数据 printf("xinzai\n"); //配置串口重定向后才可使用
HAL_UART_RxCpltCallback(huart); //stm32f1xx_hal_uart.c,3660行
//stm32f1xx_hal_uart.c,2619行
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) //中断回调函数
main.c
/* USER CODE BEGIN Includes */ #include <string.h> //26行 #include <stdio.h> //27行 /* USER CODE END Includes */ /* USER CODE BEGIN PV */ uint8_t UART_Recv_IT[5]; //48行 char UART_Str[30]; //49行 /* USER CODE END PV */ /* USER CODE BEGIN 2 */ //参数1:UART 模块的配置信息的指针,参数2:数据缓冲区的指针,参数3:接收字节长度 HAL_UART_Receive_IT(&huart1, UART_Recv_IT, 4); //串口中断接收函数,95行 /* USER CODE END 2 */ //while函数里 sprintf(UART_Str, "%d\n", 666); //102 HAL_UART_Transmit_IT(&huart1, UART_Str, strlen(UART_Str)); //串口中断发送函数,103 HAL_Delay(1000); //104 //151行开始 /* USER CODE BEGIN 4 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) //串口中断接收触发函数 { if(huart == &huart1) //判断传进来的串口是哪个 { if(strcmp("LED1", (char *)UART_Recv_IT) == 0) //字符串比较函数 { HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); memset(UART_Recv_IT,'\0',5); //替换字符函数,常用于清除指定空间 } if(!strcmp("LED2", (char *)UART_Recv_IT)) //字符串比较函数 { HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin); memset(UART_Recv_IT,'\0',5); } //因为只能接受一次串口中断,所以在串口中断触发函数需要重新调用 HAL_UART_Receive_IT(&huart1, UART_Recv_IT, 4); } } /* USER CODE END 4 */
不受接收字符长度影响,可以随意接收字符长度并判断
空闲状态:在多个字节传输结束后,通信线路将会维持高电平,这个状态称为空闲状态(没有数据传输时的空闲状态,数据传输刚结束的空闲状态)
空闲中断产生条件:在数据传输过程中,当CPU检测到通信线路处于空闲状态时,且空闲状态的持续时间大于一个字节传输时间时,空闲状态标志IDLE将由硬件置1,产生空闲中断
//stm32f1xx_hal_uart.h,2710行
__weak void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) //空闲中断接收回调函数
main.c
/* USER CODE BEGIN Includes */ #include <string.h> //27行 /* USER CODE END Includes */ /* USER CODE BEGIN PD */ #define RECV_Size 100 //37行 /* USER CODE END PD */ /* USER CODE BEGIN 2 */ HAL_UARTEx_ReceiveToIdle_DMA(&huart1, UART_Recv_IDLE, RECV_Size); //空闲中断接收函数,94行 //数据接收RECV_Size一半时会重新触发中断,需要关闭DMA接收中断使能 HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //96行 /* USER CODE END 2 */ //150行 void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) //空闲中断接收触发函数 { if(huart == &huart1) //判断传进来的串口是哪个 { if(strcmp("LED1", (char *)UART_Recv_IDLE) == 0) //字符串比较函数 { HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); memset(UART_Recv_IDLE,'\0',Size); //替换字符函数,常用于清除指定空间 } if(!strcmp("LED2ON", (char *)UART_Recv_IDLE)) //字符串比较函数 { //HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin); HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, 0); memset(UART_Recv_IDLE,'\0',Size); }else if(!strcmp("LED2OFF", (char *)UART_Recv_IDLE)) { HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, 1); memset(UART_Recv_IDLE,'\0',Size); } //因为只能接受一次串口中断,所以在串口中断触发函数需要重新调用 HAL_UARTEx_ReceiveToIdle_DMA(&huart1, UART_Recv_IDLE, RECV_Size); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。