使用printf函数
STM32 HAL库 UART使用printf
MDK设置:勾选Use Micro LIB(忘记勾选,结果半天没反应)
主函数中添加如下代码
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart3, &ch, 1, 0xffff);
return ch;
}
/* USER CODE BEGIN 0 */
//1、首先要在你的main 文件中 包含“stdio.h” (标准输入输出头文件)
#include <stdio.h>
//2、在main文件中重定义<fputc>函数 如下:
// 发送数据
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch, 1, 0xFFFF);// USART1 可以换成 USART2 等
while (!(USART1->SR & UART_FLAG_TXE));
return (ch);
}
// 接收数据
int GetKey (void) {
while (!(USART1->SR & UART_FLAG_RXNE));
return ((int)(USART1->DR & 0x1FF));
}
/* USER CODE END 0 */
printf("\n\r while循环中!!!\n\r");
DMA串口接收发送数据
STM32—cubeMX+DMA+USART 接收任意长度的数据
1、串口初始化
CubeMx自动生成,在USERcode添加
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static 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 = 115200;
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_ENABLE_IT(&huart1, UART_IT_IDLE);//使能idle中断
HAL_UART_Receive_DMA(&huart1,rx_buffer,buffsize);//打开DMA接收,数据存入rx_buffer数组中。
/* USER CODE END USART1_Init 2 */
}
2、接收中断处理
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
uint32_t tmp_flag = 0;
uint32_t temp;
tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
if((tmp_flag != RESET))//idle标志被置位
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
temp = huart1.Instance->SR; //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
temp = huart1.Instance->DR; //读取数据寄存器中的数据
HAL_UART_DMAStop(&huart1); //
temp = hdma_usart1_rx.Instance->NDTR;// 获取DMA中未传输的数据个数,NDTR寄存器分析见下面
rx_len = buffsize - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
recv_end_flag = 1; // 接受完成标志位置1
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
3、主循环函数
while (1)
{
if(recv_end_flag ==1)
{
// printf("\n\r while循环中!!!\n\r");
printf("rx_len=%d\r\n",rx_len);//打印接收长度
// PackageSendData((uint8_t *) rx_buffer, &rx_len);
HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);//接收数据打印出来
for(uint8_t i=0;i<rx_len;i++)
{
rx_buffer[i]=0;//清接收缓存
}
rx_len=0;//清除计数
recv_end_flag=0;//清除接收结束标志位
}
HAL_UART_Receive_DMA(&huart1,rx_buffer,buffsize);//重新打开DMA接收
}
打包发送数据
/***********************************************************************************************************
* 函数名称: PackageSendData()
* 输入参数: data,要发送的数据的首地址; *len,发送数据的总长度
* 返回值 : 无
* 功 能: 根据通信协议,封装要发送的数据
************************************************************************************************************/
void PackageSendData(u8* data, u8* len)
{
u8 temp[64],temp1[64],i,j = 0;
u16 crc;
memset(&temp[0], 0, sizeof(temp));
memset(&temp1[0], 0, sizeof(temp1));
memcpy(&temp[2], data, *len); //复制传输数据
temp[0] = FrameHeader; //加入帧头
temp[1] = *len+3; //加入长度值
crc = CRC16MODBUS(&temp[1], *len+1); //计算CRC16校验值
memcpy(&temp[*len+2], &crc, 2); //复制校验值
for(i=3; i < *len+3+j; )
{
if((temp[i]==FrameHeader)||(temp[i]==FrameEnd))//如果传输的数据中有和帧头或帧尾一样的数据则插入转义符
{
memset(&temp1[0], 0, sizeof(temp1));
memcpy(&temp1[0], &temp[i], *len+3+j-i);
temp[i] = 0x5C; //加入转义符 ‘\'
memcpy(&temp[i+1], &temp1[0], *len+3+j-i);
i = i+2;
j++;
}
else
i++;
}
temp[*len+4+j] = FrameEnd;
memcpy(data, &temp[0], *len+5+j);
*len = *len+5+j;
}
/* UART_Transmit test BEGIN 串口数据发送测试*/
u8 cnt;
cnt = 5;
u8 uart2BUF[32] = {0X2A,0X2B,0x2C,0x2D,0x2E,0x2F,0x21,0x22};
PackageSendData((uint8_t *) uart2BUF, &cnt);
HAL_UART_Transmit(&huart2,(uint8_t *)uart2BUF,cnt,0XFF);
/* UART_Transmit test END*/
接收指定协议数据
验证接收数据有效性
发送 01 02
打包后数据为 9A 05 01 02 E1 90 9B
/***********************************************************************************************************
* 函数名称: UnpackReceivedData()
* 输入参数: data,要解包的数据的首地址,*len 要解包的数据的总长度(不包括帧头和帧尾)
* 返回值 : 1, 数据有效, 0,数据无效。
* 功 能: 解包接收到的数据并判断数据有效性
************************************************************************************************************/
u8 UnpackReceivedData(u8* data, u8* len)
{
u16 crc,crctemp;
memcpy(&crctemp,(data+*len-3),2); //复制数据中的CRC校验值
printf("crctemp=%d\r\n",crctemp);
crc = CRC16MODBUS(data, *len-3); //计算数据的CRC16校验值
printf("crc=%d\r\n",crc);
if(crctemp == crc) //校验值正确
return 1;
return 0;
}
CRC校验范围为数据长度位 + 数据 不包括帧头