你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

再次质疑 HAL_UART_Receive_IT函数  

[复制链接]
GKoSon 提问时间:2018-4-19 17:38 /
最近准备搞STM32L471 而以前103/107都是基于标准库写的。现在没办法了,用HAL库,而CUBEMX软件则是打开了新世界的大门。
看网上的教程 果然遇到了评论中的问题。http://www.waveshare.net/study/article-644-1.html
只能执行一次,就不行了。在论坛我也找到了曾经的讨论https://www.stmcu.org.cn/module/forum/thread-604716-1-1.html
现在小弟在此表达一下这个问题。
第一步建立工程(107已经被我上个帖子搞坏了,用103吧)
1.png
第二部左边使能3处
2.png
第三部时钟
3.png
第四部使能中断 默认的115200 N 8 1不改
4.png
最后设置一下 就生成代码。

现在板子3根线连接:PC用一个驱动CH340的 串口转UART PCGND---板子GND  PC TC--板子 RX  PC RX--板子 TX 打开串口助手准备实验。
先来简单的:直接输出
uint8_t ch=0xAb;//1
uint8_t aRxBuffer[]="hello GKoSon\r\n";//2
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch,       1, 0xFFFF);//3
HAL_UART_Transmit(&huart1, (uint8_t *)aRxBuffer, 10,0xFFFF);//4

  while (1)
  {。。。

上面增加的1234就可以完成直接输出调试信息了。【举例不好 也就算了吧】
5.png
现在开始接受,准备用中断接收。

CASE1
uint8_t ch=0xAb;//1
uint8_t aRxBuffer[10]="0123456789";//2
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
//HAL_UART_Transmit(&huart1, (uint8_t *)&ch,       1, 0xFFFF);//3
//HAL_UART_Transmit(&huart1, (uint8_t *)aRxBuffer, 10,0xFFFF);//4
HAL_UART_Transmit_IT(&huart1, (uint8_t *)aRxBuffer, sizeof(aRxBuffer));//5
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 10);//6

  while (1)
  {}

在上面的1234以后增加2局用于中断收发的使能。
在main.c最后重写回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)aRxBuffer, 10,0xFFFF);
}


此时效果:跑起来--板子给串口发送成功---串口给板子发送很多A但是板子只能返回一次!
6.png

CASE2
为什么只有第一次是成功的? 现在在while一直调用函数HAL_UART_Receive_IT
也就是修改为
   while (1)
  {
        HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 10);
        HAL_Delay(100);
  }

现在是成功了 问题是这肯定不行的 轮训还弄啥嘞。

CASE3
还是放弃上面的,依然用while(1){}这样,不轮询。
参考别人的 ,在每次接收的回调函数里面
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)aRxBuffer, 10,0xFFFF);
          HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 10);
}

实际效果跟CASE1是一样的,第一次成功以后就不行了。
注意到这个其实中断每次是只接收1个u8的,所以改成10位1就可以了。
也就是:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
          HAL_UART_Transmit(&huart1, (uint8_t *)aRxBuffer,       1,0xFFFF);
          HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer,   1);
}


此时蜜汁还用。

那么除了这样用1,还有没有好办法呢?
收藏 1 评论37 发布时间:2018-4-19 17:38

举报

37个回答
ringsp 回答时间:2018-9-8 07:10:01
本帖最后由 ringsp 于 2018-9-8 07:12 编辑
cczhw 发表于 2018-8-21 08:53
那是你没做好。

一大帮干单片机的,看到st的驱动库惊为高科技。用过环形队列做串口收发吗?真正理解钩子函数吗?用过链表数据结构吗?用过动态内存分配吗?对编译器和arm架构理解吗?有没有用散转文件去定义程序段和数据段的位置?用cube生成一个上百M的工程上来就可以写print hello world就是高手了?
Ankky 回答时间:2020-1-5 11:27:01
ringsp 发表于 2018-9-8 07:10
一大帮干单片机的,看到st的驱动库惊为高科技。用过环形队列做串口收发吗?真正理解钩子函数吗?用过链表 ...

建议赶紧去医院检查一下脑子。
ringsp 回答时间:2018-8-12 10:20:32
没见过STM32这么蛋疼的串口,非标准16C550,纯自定义的。大多数情况下的应用都是,需要每一字节去解析协议。初始化的时候开启接收中断,只要来数据,要么满硬件FIFO触发中断,要么就是来了数据但不满FIFO触发超时中断,两种中断都可以去处理数据。而ST的HAL自以为是要么死等timeout,而把中断方式做成不断的开关中断,把很好的回调概念玩残了。而且没有硬件FIFO,容易丢字节。真不知道用STM32垃圾芯片的都是些什么应用,为了那些连环形队列数据结构都不会的人快速上手做产品?
Dandjinh 回答时间:2018-4-20 13:30:17
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, Number);意思是接收到Number个字节后,触发HAL_UART_RxCpltCallback,没收满是不会触发的。而且HAL_UART_Receive_IT是一次性的,触发完后需要时要再调用一下。条件允许的话,用DMA+空闲中断实现不定长接收。

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

废鱼 回答时间:2018-4-20 13:44:50
我之前直接修改的底层驱动,把他完成后的关闭逻辑部分删除了。。

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

myccl 回答时间:2018-4-20 15:14:47
我之前也遇到过,后来我发现只要你发送端一个个字符发送就不会出现问题,中断可以一直触发,

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

GKoSon 回答时间:2018-4-20 15:23:58
myccl 发表于 2018-4-20 15:14
我之前也遇到过,后来我发现只要你发送端一个个字符发送就不会出现问题,中断可以一直触发, ...

也就是你的方法跟我一样  用 1
myccl 回答时间:2018-4-20 16:15:15
与龙共舞 发表于 2018-4-20 15:23
也就是你的方法跟我一样  用 1

不是,是在串口助手里一个个字符发。。。
GKoSon 回答时间:2018-4-20 16:22:47
myccl 发表于 2018-4-20 16:15
不是,是在串口助手里一个个字符发。。。

不用这么麻烦的。。。
myccl 回答时间:2018-4-20 16:24:12
与龙共舞 发表于 2018-4-20 16:22
不用这么麻烦的。。。

可是之前我试过像你一样将10改1,还是不行啊
zhao.zhao 回答时间:2018-4-20 16:44:52
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 10);//6
这个函数是每次串口1接收到了设置的10个字节,进入串口接收中断回调函数HAL_UART_RxCpltCallback,
譬如发送15个字节,前10个字节收到后,进入函数HAL_UART_RxCpltCallback,后5个字节没满10个字节,不会进入的

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

GKoSon 回答时间:2018-4-23 09:23:44
第015章 STM32外设之D[00_30_43][20180422-180330-0]
QQ截图20180423092319.png
jjbboox 回答时间:2018-4-23 09:39:43
放在轮询里面又有何不可呢?
反正当上次接收还没有结束的时候调了也没用,但是当上次接收结束了,调一下又进入接收状态了呀,本来HAL库就是这么设计的。
非要在中断回调中再开启中断接收,似乎没有必要。而且万一这个时候由于其他原因串口接收被占了,你调用中断接收失败,整个链条就断了。还是放在while(1)中保险。

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

uglyclown 回答时间:2018-7-7 15:51:43
zhao.zhao 发表于 2018-4-20 16:44
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 10);//6
这个函数是每次串口1接收到了设置的10个字节 ...

那为什么把10改成1就好了
zhao.zhao 回答时间:2018-8-12 10:41:30
uglyclown 发表于 2018-7-7 15:51
那为什么把10改成1就好了

传统串口应该是接收1个字节,中断一次,如果你的程序是这样设计的,就把10改成1就可以了。
其实本质上这个串口也是接收1个字节,中断一次的,只不过接收的字符没有达到用户设定的数量时,它没有进入接收中断回调函数。
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 10);
用上面这个函数设置也就在接收定长帧数据时比较方便。不定长的帧数据为了避免遗漏数据,确实要把10改成1的。
ringsp 回答时间:2018-8-12 11:59:57
zhao.zhao 发表于 2018-8-12 10:41
传统串口应该是接收1个字节,中断一次,如果你的程序是这样设计的,就把10改成1就可以了。
其实本质上这 ...

改成1之后,如果在接收回调函数里面做数据解析并给线程发送消息,那么很可能紧接着的第二个字节overflow,因为串口只有1个字节的硬件FIFO,非常奇怪st的库用的那么广,难道大家都没遇到问题吗?
123下一页

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版