最近在调试stm32l0系列单片机串口程序,发现STM官方提供的HAL库中的串口函数只能接收定长数据。
这种情况明显在不改变串口协议的情况下,是无法与外设进行通信的,所以粗略的修改了一下程序,使之实现不定长接收。
如有错误,请随时指出啊哈哈哈哈哈!
恩,首先先介绍一下HAL库的串口函数的用法吧。
HAL库的串口发送比较简单:
//把TxData的内容通过uart2发送出去,0xffff是超时时间
HAL_UART_Transmit(&huart2,TxData,sizeof(TxData),0xffff);
HAL库提供的串口函数一共有三种用法:
1.接收定长数据
//通过uart2接收10个数据,知道串口接收到10个数据后再返回
HAL_UART_Receive_IT(&huart2,(uint8_t *)&value,10)
2.接收定长数据并设置超时时间
//通过uart2接收10个数据,1000是超时时间,表示1000MS内没有接收到10个数据也返回,timeout的时间是最大值0xffff
HAL_UART_Receive(&huart2,(uint8_t *)&value,10,1000);
3.DMA接收
HAL_UART_Receive_DMA(&huart2, (uint8_t *)rxData, sizeof(rxData)-1)
数据接收后,就可以在回调函数里处理数据了。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle);
可以从以上函数可以看到,每种接收方式都要输入接收数据的长度。但是对于不知道对方发来数据长度的情况几乎就没有很好的解决办法。
于是想到可以不可以绕过数据长度判断,不管多少数据全部接收,再通过FIFO传出数据进行处理。
其中串口的通信协议就自己定了,但是最好有数据长度。
在main函数的while(1)前使能串口
struct kfifo recvfifo;
uint8_t USART_Receive_Buf[64]; //长度需2的n次方,以便后续与操作等效取余操作
void Uart_start(void)
{
uint8_t bRxBuffer[20];
if(HAL_UART_DeInit(&huart2) != HAL_OK)
{
Error_Handler();
}
if(HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
//这个20随便写,因为已经没用了
if(HAL_UART_Receive_IT(&huart2, (uint8_t *)bRxBuffer, 20) != HAL_OK)
{
Error_Handler();
}
}
void Uart_Handle(void)
{
uint8_t len = 0;
unsigned char check = 0;
uint8_t revcmdstr[CMD_LEN] = {0};
uint8_t rec_len = __kfifo_len(&recvfifo); //读取接收到FIFO里的数据长度
if (rec_len >= 16) //长度大于16(通信协议自己定)
{
if ( recvfifo.buffer[(recvfifo.out + UF_START) & (recvfifo.size - 1)] = 0x55) //校验协议头
{
len = recvfifo.buffer[(recvfifo.out + UF_LEN) & (recvfifo.size - 1)]; //获取数据长度
if (rec_len >= len)
{
__kfifo_get(&recvfifo, revcmdstr, len); //获取数据
Request_Cmd(revcmdstr);
}
}
else
{
__kfifo_get(&recvfifo, revcmdstr, 1);//如果当前位置不是命令起始标志,则丢弃数据
}
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init();
uint8_t aRxBuffer[20];
strcpy((char *)aRxBuffer, "SYSTEM START");
if(HAL_UART_Transmit(&huart2, (uint8_t*)aRxBuffer, 13, 5000)!= HAL_OK)
memset( (char *)aRxBuffer, '\0', sizeof(aRxBuffer) );
Uart_start();
kfifo_init(&recvfifo); //初始化FIFO
while(1)
{
Uart_Data();
HAL_Delay(1);
}
}
修改库文件
//stm32l0xx_hal_uart.c
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
uint16_t* tmp;
uint16_t uhMask = huart->Mask;
uint16_t uhdata;
uint8_t temdata;
/* Check that a Rx process is ongoing */
if(huart->RxState == HAL_UART_STATE_BUSY_RX)
{
uhdata = (uint16_t) READ_REG(huart->Instance->RDR);
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))//字长为9位,无奇偶校验
{
tmp = (uint16_t*) huart->pRxBuffPtr ;
*tmp = (uint16_t)(uhdata & uhMask);
huart->pRxBuffPtr +=2;
}
else
{
// *huart->pRxBuffPtr++ = (uint8_t)(uhdata & (uint8_t)uhMask); //读取数据
temdata = (uint8_t)(uhdata & (uint8_t)uhMask);
__kfifo_put_singlebyte(&recvfifo, temdata);
}
SET_BIT(huart->Instance->CR3, USART_CR3_EIE);
SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
return HAL_OK;
}
else
{
/* Clear RXNE interrupt flag */
__HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
return HAL_BUSY;
}
}
在工程中加入FIFO文件
#include "kfifo.h"
void *memcpy(void *__dest, void *__src, int __n)
{
int i = 0;
unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
for (i = __n >> 3; i > 0; i--) {
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (__n & 1 << 2) {
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (__n & 1 << 1) {
*d++ = *s++;
*d++ = *s++;
}
if (__n & 1)
*d++ = *s++;
return __dest;
}
void kfifo_init(struct kfifo *fifo)
{
fifo->buffer = USART_Receive_Buf;
fifo->size = sizeof(USART_Receive_Buf)/sizeof(uint8_t);
fifo->in = fifo->out = 0;
}
unsigned int __kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
{
unsigned int l;
len = min(len, fifo->size - fifo->in + fifo->out);
/* first put the data starting from fifo->in to buffer end */
l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
/* then put the rest (if any) at the beginning of the buffer */
memcpy(fifo->buffer, buffer + l, len - l);
fifo->in += len;
return len;
}
void __kfifo_put_singlebyte(struct kfifo *fifo, unsigned char data)
{
fifo->buffer[(fifo->in++) & (fifo->size - 1)] = data;
}
unsigned int __kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len)//unsigned char
{
unsigned int l;
len = min(len, fifo->in - fifo->out);
/* first get the data from fifo->out until the end of the buffer */
l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
/* then get the rest (if any) from the beginning of the buffer */
memcpy(buffer + l, fifo->buffer, len - l);
fifo->out += len;
return len;
}
#ifndef KFIFO_H
#define KFIFO_H
/* Includes ------------------------------------------------------------------*/
#include "stm32l0xx_hal.h"
#ifndef min
#define min(x,y) ((x) < (y) ? x : y)
#endif
struct kfifo {
unsigned char *buffer; /* the buffer holding the data */
unsigned int size; /* the size of the allocated buffer */
unsigned int in; /* data is added at offset (in % size) */
unsigned int out; /* data is extracted from off. (out % size) */
};
static inline unsigned int __kfifo_len(struct kfifo *fifo)
{
return fifo->in - fifo->out;
}
extern struct kfifo recvfifo;
extern uint8_t USART_Receive_Buf[64];
extern void kfifo_init(struct kfifo *fifo);
extern unsigned int __kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len);
extern void __kfifo_put_singlebyte(struct kfifo *fifo, unsigned char data);
extern unsigned int __kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len);
#endif
参考资料:
http://www.cnblogs.com/Mysterious/p/4804188.html