Chinaunix首页 | 论坛 | 博客
  • 博客访问: 84620
  • 博文数量: 44
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 582
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-05 15:21
个人简介

读圣人书,明圣人志,遵圣人训。

文章分类

全部博文(44)

文章存档

2017年(23)

2016年(19)

2014年(2)

我的朋友

分类: 嵌入式

2016-12-02 18:30:40

                                            STM32CubeMX--01—INT
                                                                          -------- 转载请注明出处
                                                                          -------- 更多笔记请访问我的博客:merafour.blog.163.com 
                                                                          -------- 2016-11-30.冷月追风

                                                                                                   -------- email 



         :不特别声明的情况下不区分 UART跟 USART,统称 UART。 
         面我们讲了 UART的轮训方式,现在我们来看看在 HAL中如何使用中断方式来接收数据。
中断方式接收数据首先要勾选UART中断:
 STM32CubeMX-[01]-UART-INT - 乐山居士 - 有生之年
           断优先级是可以设置的,我这里使用 MX分配的优先级。那么我们该如何接收数据呢?答案是重定义"HAL_UART_RxCpltCallback"函数,而通过 "HAL_UART_Receive_IT"函数启动接收,即打开中断:
 HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
        管我们看到其形参可以设置接收数据长度,但由于我们只能通过 "HAL_UART_RxCpltCallback"函数知道数据接收完了,个人觉得意义并不是很大,比如设置长度为8,但倘若只接收到一个数据呢?难道就不处理了吗?显然是不行的。或者本来我是发了 8个数据的,但由于干扰在接收数据之前就接收到了一个错误的数据,此时实际上可以接收到 9个数据,但返回的确实一个不完整的包。而如果是接收单个字节由于校验机制我们会知道后面 8个字节才是一个完整的数据包。因此建议接收数据长度设置为 1:
 HAL_UART_Receive_IT(&huart1, &pData, 1);
    后中断回调函数为:
 uint8_t pData=0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Transmit(&huart1, &pData, 1, 0);
HAL_UART_Receive_IT(&huart1, &pData, 1);
}
   
         住,在中断回调函数中我们需要再次调用 HAL_UART_Receive_IT函数,否则下一次就接收不到信号了。
我个人对于这种使用方式并不喜欢,原因很简单:效率太低了。所以我倾向于打破现有的机制,即直接接手串口中断:"USART1_IRQHandler"函数。比如,我自己写一个函数:
 void terminal1_data_process(uint8_t data)
{
HAL_UART_Transmit(&huart1, &data, 1, 1);
}
   
然后呢:
 void USART1_IRQHandler(void)
{
terminal1_data_process(USART1->RDR & 0xFF);
HAL_UART_IRQHandler(&huart1);
}
        后再打开中断我们就可以接收数据了:"__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);"。其实我们还可以把 HAL_UART_IRQHandler替换成清楚标志的操作,这样执行起来会更快一些。
上面的 "terminal"函数虽然接收到了数据,但实际上我们需要做一些处理才方便使用,原因是我们不可能每来一个字节就处理一个字节,而中断当中实际上也不适合做一些过于耗时的处理,应尽量简短。所以我们应该将函数写成:
 void terminal1_data_process(uint8_t data)
{
macro_queue_write(data,cache1_terminal);
}
   
         后在主循环中读取 cache1_terminal中的数据:
 while (1)
{
if(0==cache_queue_read_byte(&cache1_terminal, &_byte))
{
HAL_UART_Transmit(&huart1, &_byte, 1, 1);
}
HAL_Delay(1);
}
       们可以根据需要设置 cache1_terminal的大小,而且这样我们可以收到一串数据之后批量处理。
 #define macro_queue_write(_byte,_queue) do{ \
_queue.w_tmp = _queue.index_w+1; \
if(_queue.w_tmp>=sizeof(_queue.buf)) _queue.w_tmp=0; \
_queue.buf[_queue.w_tmp] = _byte; \
if(_queue.w_tmp != _queue.index_r) _queue.index_w=_queue.w_tmp; \
}while(0);

static __inline int cache_queue_read_byte(cache_queue* _cache, uint8_t* _byte)

{
int ret=-1;
_cache->r_tmp = _cache->index_r+1;
if(_cache->r_tmp>=sizeof(_cache->buf)) _cache->r_tmp=0;
if(_cache->r_tmp != _cache->index_w)
{
*_byte = _cache->buf[_cache->r_tmp];
_cache->index_r = _cache->r_tmp;
ret = 0;
}
return ret;
}

#define CACHE_QUEUE_LEN 256

typedef struct{
uint16_t index_r;
uint16_t index_w;
uint16_t w_tmp;
uint16_t r_tmp;
uint8_t buf[CACHE_QUEUE_LEN];
}cache_queue;
   
         是我们刚刚写入跟读取 cache1_terminal的代码。
         过需要注意的是 HAL的 "HAL_UART_Transmit"函数的形参 Timeout设置 0与非 0经测试并不是随意的,有时候 0会死掉,有时候又是非 0会死掉。
附录:
        :
阅读(1798) | 评论(0) | 转发(0) |
0

上一篇:STM32CubeMX-[01]-UART-Poll

下一篇:音乐收藏

给主人留下些什么吧!~~