完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
前言
关于赛元单片机触摸的那篇文章确实帮助到过一些网友,后来有网友私信说赛元单片机的三合一串口功能遇到了问题,考虑到我之前的项目中用到过这个串口,也调通了,便想写下这篇文章,目的是帮助遇到问题的网友,以及记录学习的过程。 所用单片机型号:SC92F8463B(同系列的都可以参考本篇文章),主频:12Mhz 之前用过STM32F103C8T6的单片机,在那次的使用经历中,第一次了解并学习到了串口的使用方法,当时的项目中,参考的是原子哥的示例代码进行串口的收发,后面测试的过程中,发现串口功能会影响到其它的功能。在老工程师的指导下,才了解到,原子哥的串口发送方式是不太适用于工作中的项目的,原因也很简单,以阻塞的方式发送数据帧,再说直白一点,通过while()查询标志位以此完成数据的发送。 因此,我便想先介绍一种不一样的数据发送方式! 中断的方式发送数据 使用串口时,经常会用到以中断的方式接受数据,但很少使用以中断的方式发送数据,网上相关的资料也很少。但是这是一种非常好的方式,特别是在实际的工作中,会更加深刻的体会到这一点。而且不论是51单片机还是基于ARM的单片机,我所使用过的单片机都能以中断的方式发送数据。 先来看看SC92F846XB的规格书 先看第一幅图中红框里的内容:发送和接收完成时可产生中断RI/TI,该中断标志需要软件清除。 接收就不说了,用过串口的都清楚这个方式,主要说发送,我来大致描述一下以中断发送数据这个过程: 整个发送的过程其实非常简单和顺畅,而且单片机的效率也能达到最高。 再来对比下查询的方式进行发送: 从流程图中应该会比较容易看出这两种发送方式的区别。采用中断方式发送时,可以说全是优点,莫得缺点~ 代码示例 本文主要是为了解决网友的问题,再搞清楚中断发送这件事后,以三合一串口为例,从初始化开始,到发送一帧数据结束,来完整的演示一下。 准备工作 前提条件:需要在main()函数中定时调用uart1_start_trans()函数,推荐500ms,1000ms。 实验现象:每间隔一次定时时长,会在串口助手中接收到data_for_tx中的数据。 宏定义及全局变量 //相关宏定义 #define SYSTEM_CLK ((unsigned long int)12000000) #define UART1_BAUD_9600_LOAD_VALUE 9600 static u8 data_for_tx[5] = {0x11, 0x22, 0x33, 0x44, 0x55}; //定义一个待发送数据的数组 初始化 /*************************************************************/ /*函数名:hw_uart1_init /*输 入:无 /*输 出:无 /*功 能:初始化串口1的IO口,波特率9600并开启中断; /*************************************************************/ void hw_uart1_init(void) { P2CON &= 0xFC; //TX/RX设置为输入带上拉 P2PH |= 0x03; OTCON |= 0xC0; //串行接口SSI选择Uart1通信 SSCON0 = 0x50; //设置通信方式为模式一,允许接收 SSCON1 = SYSTEM_CLK/UART1_BAUD_9600_LOAD_VALUE; //波特率低位控制 SSCON2 = (SYSTEM_CLK/UART1_BAUD_9600_LOAD_VALUE)>>8; //波特率高位控制 IE1 |= 0x01; //开启SSI中断 IP1 |= 0x01; //中断优先级设置为高 EA = 1; } 这部分没啥可说的,就是按照示例代码和规格书写的。 中断服务函数 /*************************************************************/ /*函数名:uart1_isr /*输 入:无 /*输 出:无 /*功 能:串口1中断服务函数,以中断方式进行收发; /*************************************************************/ void uart1_isr(void) interrupt 7 { u8 temp_char = 0; if(SSCON0&0x02) //发送标志位判断 { SSCON0 &= 0xFD; //清中断 uart1_send_data(); //发送逻辑 } if((SSCON0&0x01)) //接收标志位判断 { SSCON0 &= 0xFE; //清中断 temp_char = SSDAT; uart1_receive_data(temp_char); //接收逻辑 } } 中断服务函数其实是很简洁的,这里不再介绍接收逻辑的编写,只说发送逻辑的函数,以中断方式发送数据的重点也在这里~ 发送逻辑函数 /*************************************************************/ /*函数名:uart1_send_data /*输 入:无 /*输 出:无 /*功 能:发送逻辑判断,控制发送数据; /*************************************************************/ void uart1_send_data(void) { static u8 index = 0; //函数内部局部变量,用做待发送数组的下标 if(index>=5) { index = 0; } else { SSDAT = data_for_tx[index++]; } } 分析一下这个过程:index的初始值为0,在发送逻辑函数中,会将data_for_tx[0]写入数据寄存器,物理层会发送data_for_tx[0],index变为1;发送完毕后,便会再次进入发送中断函数,调用在发送逻辑函数时,会将data_for_tx[1]写入数据寄存器,物理层会发送data_for_tx[1],index变为2,循环几次后index变为5时,data_for_tx数组中的5个元素都已经发送完毕了(即这一帧数据发送完毕),这时已经不需要再发送了,需要做的仅仅是将index给清零,等待main函数中启动下一帧数据的发送。 以上是理解发送中断的重点,一遍看不懂就多看几遍,也可以自己动手画一画流程图。 启动发送函数 /*************************************************************/ /*函数名:uart1_start_trans /*输 入:无 /*输 出:无 /*功 能:启动串口1发送; /*************************************************************/ void uart1_start_trans(void) { SSCON0 |= 0x02; //手动置位发送中断标志位,进入发送中断,启动发送 } |
|
|
|
只有小组成员才能发言,加入小组>>
3310 浏览 9 评论
2991 浏览 16 评论
3492 浏览 1 评论
9055 浏览 16 评论
4086 浏览 18 评论
1174浏览 3评论
603浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
596浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2333浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1894浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-21 14:16 , Processed in 1.182416 second(s), Total 78, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号