串口windows正常ubuntu

串口windows正常ubuntu,第1张

您好,串口在Windows和Ubuntu上的工作原理是相同的,但是它们的实现方式不同。Windows使用COM端口来实现串口通信,而Ubuntu使用USB端口来实现串口通信。在Windows上,可以使用专用的串口软件来实现串口通信,而在Ubuntu上,可以使用Linux内核中提供的串口驱动程序来实现串口通信。此外,在Windows上,可以使用设备管理器来查看和配置串口设备,而在Ubuntu上,可以使用udev规则来查看和配置串口设备。

Linux发行版自带usb to serial驱动,以模块方式编译驱动,在内核源代码目录下运行Make MenuConfig选择Devces

drivers-->USB seupport--><M>USB Serial Converter support

--><M>USB driver for GSM and CDMA modems &[*]USB Generic

Serial Driver,保存退出。运行make

modules,编译成功后可找到usbtoserial.ko及option.ko两个驱动(2.6以上内核版本模块驱动用.ko表示)。

数据传输中会出现乱码,很有可能是数组溢出,或者定义的数组长度不够。或者中断被打断。

异常二:程序卡在中断函数里面无法跳出执行主函数的逻辑

中断标志位没有被清除,在这里要注意一点,串口中断标志位自动清空的前提是软件需要先读USART_SR寄存器,然后读USART_DR寄存器来自动清除。即串口中断事件发生后,如果使能的接收中断,而中断函数里面什么都不执行的话,接收中断标志位是无法自动清空的,故而,函数会一直卡在中断函数里面。

比如一下这个函数,该函数没有逻辑问题,但会引发以上问题,代码如下

extern unsigned char star_time_led //计时开始变量

unsigned char recv_flag = 0//定义接受标志位

unsigned long recv_cnt = 0//串口1接收数据缓存

unsigned char recv_buf[MAX_REV_NUM]//串口1接收数据缓存

extern unsigned char star_time

extern unsigned char recv_time_cnt

/*

以下写法有严重问题

如果没有这句函数→USART_ClearFlag(USART1,USART_FLAG_RXNE)//清空中断标志位

串口接收中断标志位将文法被清空,会导致函数卡在中断函数里面一直循环,无法正常运行主函数

原因分析:

中断条件成立后,中断标志位将会标记,程序将会进入中断函数运行,软件自动轻触中断标志位的条件是

先读USART_SR寄存器,再读USART_DR寄存器。

void USART1_IRQHandler(void)//串口1中断服务程序

{

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //是否发送中断事件

{

star_time = 1//接受到一帧数据的时候,打开软件定时器,去计数

if(recv_cnt <MAX_REV_NUM)//数组长度是否超过缓存区

{

recv_buf[recv_cnt] =USART_ReceiveData(USART1)//将接收到的数据存在数组Usart1RecBuf[RxCounter]里

recv_cnt++

}

else

{

recv_cnt = MAX_REV_NUM

//限制数组长度,超过缓存区则不再接收

}

recv_time_cnt = 0//每接收到一帧数据,把定时计数器清零,相当于喂狗

//但是在定时器中断里面会不断的累加

USART_ClearFlag(USART1,USART_FLAG_RXNE)//清空中断标志位

}

}

*/

上述代码优化后如下

void USART1_IRQHandler(void)//串口1中断服务程序

{

static char ch

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //是否发送中断事件

{

ch = USART_ReceiveData(USART1)//将接收到的数据存在数组Usart1RecBuf[RxCounter]里

star_time = 1//接受到一帧数据的时候,打开软件定时器,去计数

if(recv_cnt <MAX_REV_NUM)//数组长度是否超过缓存区

{

recv_buf[recv_cnt] =ch//将接收到的数据存在数组Usart1RecBuf[RxCounter]里

recv_cnt++

}

else

{

recv_cnt = MAX_REV_NUM

//限制数组长度,超过缓存区则不再接收

}

recv_time_cnt = 0//每接收到一帧数据,把定时计数器清零,相当于喂狗

//但是在定时器中断里面会不断的累加

USART_ClearFlag(USART1,USART_FLAG_RXNE)//清空中断标志位

}

}

异常三:数据发送中间歇性数据异常漏发乱发等

对于这些奇奇怪怪的问题,首先要了解一下发送函数是怎么发送的

USART_DR 包含了已发送的数据或者接收到的数据。USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送 *** 作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取 *** 作时,向 USART_DR读取数据会自动提取 RDR 数据。

TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。

当 TDR 内容转移到发送移位寄存器,还没有发送出去的,就再次把TDR 内容转移到发送移位寄存器里,就会出现少发的现象。

什么时候会有这种情况呢?错误 *** 作代码如下:

void USART2_IRQHandler(void)//串口2中断服务程序

{

if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //是否发送中断事件

{

Usart1RecBuf[RxCounter] =USART_ReceiveData(USART2)//将接收到的数据存在数组Usart1RecBuf[RxCounter]里

RxCounter++//指向数组地址自加

if(RxCounter==2)

{

USART_SendData(USART1, Usart1RecBuf[0])//发送Usart1RecBuf[0]

USART_SendData(USART1, Usart1RecBuf[1])//发送Usart1RecBuf[1]

USART_SendData(USART1, Usart1RecBuf[2])//发送Usart1RecBuf[2]

}

}

}

上述代码连续运行了3次USART_SendData(USART1, Usart1RecBuf)这个函数,这种情况一般都会出现只有最后一个数据发送成功出去。原因可能就是数据还没有发送出去,发送移位寄存器就更新了。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11730617.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-18
下一篇 2023-05-18

发表评论

登录后才能评论

评论列表(0条)

保存