GKoSon 发表于 2018-4-19 17:38:26

再次质疑 HAL_UART_Receive_IT函数

最近准备搞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吧)

第二部左边使能3处

第三部时钟

第四部使能中断 默认的115200 N 8 1不改

最后设置一下 就生成代码。

现在板子3根线连接:PC用一个驱动CH340的 串口转UART PCGND---板子GNDPC TC--板子 RXPC 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就可以完成直接输出调试信息了。【举例不好 也就算了吧】

现在开始接受,准备用中断接收。

CASE1
uint8_t ch=0xAb;//1
uint8_t aRxBuffer="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但是板子只能返回一次!


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,还有没有好办法呢?

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+空闲中断实现不定长接收。

废鱼 发表于 2018-4-20 13:44:50

我之前直接修改的底层驱动,把他完成后的关闭逻辑部分删除了。。

myccl 发表于 2018-4-20 15:14:47

我之前也遇到过,后来我发现只要你发送端一个个字符发送就不会出现问题,中断可以一直触发,

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个字节,不会进入的

GKoSon 发表于 2018-4-23 09:23:44

第015章 STM32外设之Dhttps://www.stmcu.org.cn/module/forum/forum.php?mod=image&aid=412809&size=300x300&key=1cbb717b824b93bd&nocache=yes&type=fixnone

jjbboox 发表于 2018-4-23 09:39:43

放在轮询里面又有何不可呢?
反正当上次接收还没有结束的时候调了也没用,但是当上次接收结束了,调一下又进入接收状态了呀,本来HAL库就是这么设计的。
非要在中断回调中再开启中断接收,似乎没有必要。而且万一这个时候由于其他原因串口接收被占了,你调用中断接收失败,整个链条就断了。还是放在while(1)中保险。

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的库用的那么广,难道大家都没遇到问题吗?
页: [1] 2 3
查看完整版本: 再次质疑 HAL_UART_Receive_IT函数