最近用了NUCLEO的板子做一些东西,用到了串口通讯,结合一些资料再加上自己整合基本实现了发送和接收任意长度数据段(第一次写博客有点小紧张哈哈)。
首先,建立新的工程,选择芯片类型,这里我用的是stm32l073rz。
下面选择sys部分,勾选Debug Serial Wire (这个好像是下载调试 st-link,也不是很清楚)。
选择USART2,选择模式Asynchronous(异步通信)模式。
选择下面DMA模式 ,添加rx tx,并设置tx为循环模式。
勾选USART2全局中断。
保存工程,选择相应的选项,生成代码即可。
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
ch为要写入的参数,fp指向FILE结构的指针;这样重新定向后就可以使用printf直接输出。
#define RX_LEN 1024 //定义总的数据长度
volatile uint8_t RX_flag=0; //IDLE 接收标志
volatile uint8_t RX_Size=0; //接收的数据段长度
uint8_t RX_pData[RX_LEN]; //DMA 接收的数组
volatile 关键字提醒编译器定义的变量是易变的,编译后的程序每次需要存储或读取该变量时,会直接从变量地址读取数据。在中断或多线程中使用volatile关键字可以避免不同优化等级时程序出错,提高程序的鲁棒性。
void UsartReceive_IDLE(UART_HandleTypeDef *huart)
{
uint32_t temp;
uint32_t tmp_flag=0;
tmp_flag =__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE); // USART_IT_IDLE中断,是串口收到一帧数据(也可以叫做一包数据)后,发生的中断。
if((tmp_flag != RESET))//tmp_flag不等于0
{
__HAL_UART_CLEAR_IDLEFLAG(huart); //tmp_flag=0;
HAL_UART_DMAStop(huart);
temp = hdma_usart2_rx.Instance->CNDTR; //cndtr为未传输的数据
RX_Size = RX_LEN - temp; //总数减去未传输的,得到发送的数据长度
RX_flag=1;
}
}
在中断请求函数加入自定义的中断函数。
void USART2_IRQHandler(void)//串口中断请求
{
/* USER CODE BEGIN USART2_IRQn 0 */
UsartReceive_IDLE(&huart2);
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
}
static void MX_USART2_UART_Init(void)//在这个中间加入使能函数 切记切记
{
/* USER CODE BEGIN USART2_Init 2 */
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);//使能idle中断
/* USER CODE END USART2_Init 2 */
}
void uart_pc_com (UART_HandleTypeDef *huart)
{
if(RX_flag ==1)
{
printf("rx_len=%d\r\n",RX_Size);//\r是回车符,\n是换行符
HAL_UART_Transmit(&huart ,RX_pData, RX_Size,200);
for(uint8_t i=0;i<RX_Size;i++)
{
RX_pData[i]=0;//清除缓存
}
RX_Size=0;
RX_flag=0;//清除结束标志位
}
HAL_UART_Receive_DMA(huart,RX_pData,RX_LEN );//打开dma数据存入rx——RX_pData
//加在 MX_USART2_UART_Init中 pc串口助手只能接受到一次数据 只有处于main函数while循环才能一直接受发送
}
在main函数的while循环里面加入此函数,并注明使用的uart。
首先uart接受数据,触发idle中断,进入中断请求函数,获取接受到的数据以及数据长度,并将标志位置1,进入主函数输出到串口助手