目录
微控制器与外部设备的数据通信,根据连线结构和传送方式的不同,可以分为两种:
并行通信和串行通信。
并行通信:数据的各位同时发送与接收,每个数据位使用一条导线,这种方式传输快,但是需要多条导线进行信号传输。
串行通信:数据一位一位地按照顺序发送与接收。这种方式仅需要一根导线,但是传输较慢
串行通信有SPI、IIC、UART等多种,最常见最通用的是UART,大多数情况下,串口通信指的是UART。
串行通信的制式有:单工、半双工、全双工三种
单工: 单工制式下,通信线的一端为发送器,一端为接收器,数据只能按照一个固定的方向传送;半双工:半双工制式下,系统的每个通信设备都由一个发送器和一个接收器组成,因而数据能从A站传送到B站,也可以从B站传送到A站,但是不能同时在两个方向上传送;
全双工:全双工方式下,系统的每端都有发送器和接收器,可以同时发送和接收,即数据可以在两个方向上同时传送。
串行通信的主要方式有两种:同步和异步
同步串行通信:使用同一个时钟,以数据块为单位传输数据
异步串行通信:每个设备有自己的时钟信号,通信双方的波特率(串口每秒钟传输的位数)需要保持一致,以字符为单位进行数据帧传送,依次传输一个帧。
配置前需要了解一下相关寄存器
SCON: 串行控制寄存器 (可位寻址)

SM0/FE:
当PCON寄存器中的SMODO/PCON.6位为1时,该位用于顿错误检测。当检测到一个无效停止位时,通过UART接收器设置该位。它必须由软件清零。
当PCON寄存器中的SMODO/PCON.6位为0时,该位和SM1一起指定串行通信的工作方式,如下表所示。

一般使用方式1,即SM0=0,SM1=1
SM2: 允许方式2或方式3多机通信控制位。暂时不用理,置0即可。
REN:介许/禁止串行接收控制位。
由软件置位REN,即REN=1为允许串行接收状态,可启动串行接收器RxD,开始接收信息。
软件复位REN,即REN=0,则禁止接收。
TB8、RB8:奇偶校验位,方式1不用用到,置0即可。
TI:发送中断请求标志位。
在方式0,当串行发送数据第8位结束时,由内部硬件自动置位.即TI=1,向主机请求中断,响应中断后TI必须用软件清零,即TI=0。
在其他方式中,则在停止位开始发送时由内部硬件置位,即TI=1,响应中断后TI必须用软件清零。
RI:接收中断请求标志位。在方式0,当串行接收到第8位结束时由内部硬件自动置位RI=1,向主机请求中断,响应中断后RI必须用软件清零,即RI=0。
在其他方式中,串行接收到停止位的中间时刻由内部硬件置位,即RI=1,向CPU发中断申请,响应中断后RI必须由软件清零
使用方式1,则需要REN置1,剩余置零即可,则加上前面的SM0=0,SM1=1,SCON应该设置为:SCON=0x50;
至于TI以及RI:
当一帧发送完成,内部硬件自动置位TI,即TI=1,请求中断处理;
当接收完一帧信息时,内部硬件自动置位RI,即RI=1,请求中断处理。
由于TI和RI以“或逻辑”关系向主机请求中断,所以主机响应中断时事先并不知道是TI还是RI请求的中断,必须在中断服务程序中查询TI和RI进行判别,然后分别处理。因此,两个中断请求标志位均不能由硬件自动置位,必须通过软件清0,否则将出现一次请求多次响应的错误。
PCON:电源控制寄存器 (不可位寻址)

SMOD:波特率选择位。
当用软件置位SMOD,即SMOD=1,则使串行通信方式1、2、3的波特率加倍;
SMOD=0,则各工作方式的波特率加倍。复位时SMOD=0。
这个寄存器只需要用到SMOD一位,默认置0;可以不用理。
STC15系列单片机的串行口1缓冲寄存器(SBUF)的地址是99H,实际是2个缓冲器,一个是
发送寄存器,一个是接收寄存器,在物理结构上是完全独立的,字节地址均为99H,通过读/写指令区区分:
串行发送时,CPU向SBUF写入数据,此时99H表示发送缓存SBUF。
串行接收时:CPU从SBUF读取数据,此时99H表示接收缓存SBUF。
数据发送:把数据扔进SBUF后,内核会自动将数据发送,内容发送完毕,TI标志位置1。数据接收:内核从串口接收到一个完整数据后,会将RI标志置1,用户用SBUF读取即可。
由于接收通道内设有输入移位寄存器和SBUF缓冲器,从而能使一帧接收完将数据由移位寄存器装入SBUF后,可立即开始接收下一帧信息,主机应在该顿接收结束前从SBUF缓冲器中将数据取走,否则前一帧数据将丢失。SBUF以并行方式送往内部数据总线。

T1x12: 定时器1速度控制位
0,定时器1是传统8051速度,12分频;
1,定时器1的速度是传统8051的12倍,不分频如果UART1/串口1用T1作为波特率发生器,则由T1x12决定UART1/串口是12T还是1T
S1ST2: 串口1(UART1) 选择定时器2作波特率发生器的控制位
0,选择定时器1作为串口1(UART1)的波特率发生器
1,选择定时器2作为串口1(UART1)的波特率发生器,此时定时器1得到释放,可以作独立定时器使用
AUXR需要用到的为以上两位,这里选择12分频,以及定时器1作为波特率发生器
则AUXR设置为:
AUXR=0x00;
头文件“reg52.h”没有定义AUXR,因此需要添加:
sfr AUXR=0x8e;
才可以使用AUXR寄存器。
IE: 中断允许寄存器 (可位寻址)

EA: CPU的总中断允许控制位
EA=1,CPU开放中断,
EA=0,CPU屏蔽所有的中断申请。EA的作用是使中断允许形成多级控制。即各中断源首先受EA控制:其次还受各中断源自己的中断允许控制位控制。
ES: 串行口中断允许位ES=1,允许串行口中断
ES=0,禁止串行口中断
则IE应设置为:
EA=1;
ES=1;
IP:中断优先级控制寄存器低 (可位寻址)
PS :串行口1中断优先级控制位。
当PS=0时,串行口1中断为最低优先级中断(优先级0)
当PS=1时,串行口1中断为最高优先级中断(优先级1)
此外,还需要配置一下波特率,我们使用的是定时器1做串口波特率发生器,因而需要设置定时器1的TH1以及TL1(设置值可参考下标),以及定时器的工作模式(8位自动重装载模式),观看我前面写的文章——定时器原理及其应用,则定时器的配置形式为:
TMOD=0x20;
TH1=0xfd;TL1=0xfd;
TR1=1;

串口设计使用中,一般需要编写三个函数:串口初始化函数、字节发送函数及串口中断服务函数
(1)初始化函数:
①配置工作模式,对TMOD寄存器编程,TMOD=0x20(8位自动重装载模式)
②计算计数初值,对THx和TLx寄存器进行赋值(波特率9600,设置THx=0xfd,TLx=0xfd)③启动定时器,即TR0或TR1置1
④设置SCON,为0x50⑤设置AUXR,为0x00
⑥使能串口中断,ES=1⑦使能总中断,即EA =1
(2)中断服务函数(串口1中断号为4):
①对接收还是发送进行判断,即RI以及TI是否为1
②若是接收,则将SBUF中的数据取走(定义变量接收),将RI清零
③相关逻辑处理
(3)字节发送函数:
①将数据赋给SBUF
②等待数据发送,此时TI=0,使用while等待至TI=1
③将TI清零
另外,特别注意需要在前面加上:
sfr AUXR=0x8e;
才可以使用AUXR。
例子:采用8位的UART模式,波特率为9600BPS,建立数据传输通道,完成以下任务:
1、系统上电后关闭蜂鸣器继电器灯设备
2、初始化发送字符串“Welcom to FSZ system!”
3、上位机发送以下命令并产生相应响应

#include "reg52.h"
sfr AUXR=0x8e;//定义寄存器
/*****************************************************************
*@Function: SelectHc573 //
*@Description:锁存器选择 //
*@Input: channel:通道选择//
*@Output:无 //
*@Return: 无 //
*@Others: 无 //
/*****************************************************************/
void SelectHc573(unsigned char channel)
{
switch(channel)
{
case 4:
P2=P2&0x1f|0x80;
break;
case 5:
P2=P2&0x1f|0xa0;
break;
case 6:
P2=P2&0x1f|0xc0;
break;
case 7:
P2=P2&0x1f|0xe0;
break;
case 0:
P2=P2&0x1f|0x00;
break;
}
}
/*****************************************************************
*@Function:InitUart //
*@Description: 串口初始化 //
*@Input: 无//
*@Output:无 //
*@Return: 无 //
*@Others: 无 //
/*****************************************************************/
void InitUart()
{
TMOD=0x20;//设置定时器模式
TH1=0xfd;//设置定时器初始值
TL1=0xfd;
TR1=1;//使能时钟
SCON=0x50;//设置串口模式
AUXR=0x00;//配置AUXR
ES=1;//使能串口中断
EA=1;//使能总中断
}
unsigned char command=0x00;//用于接收串口的数据
/*****************************************************************
*@Function: ServiceUart //
*@Description:中断服务函数 //
*@Input:无 //
*@Output: 无//
*@Return: 无 //
*@Others: 无 //
/*****************************************************************/
void ServiceUart () interrupt 4
{
if(RI==1)//如果RI=1(接收到数据)
{
command=SBUF;//将接收的数据赋值给command
RI=0;//将接收标志位RI清零
}
}
/*****************************************************************
*@Function: SendByte //
*@Description:通过串口发送一个字节 //
*@Input:dat:发送的字节 //
*@Output:无 //
*@Return:无 //
*@Others:无 //
/*****************************************************************/
void SendByte(unsigned char dat)
{
SBUF=dat;//将dat数据赋给SBUF,将数据发送出去
while(TI==0);//等待数据发送
TI=0;//将发送标志位清零
}
/*****************************************************************
*@Function: SendString //
*@Description: 字符串发送函数 //
*@Input: *str:发送的字符串首地址//
*@Output:无 //
*@Return: 无 //
*@Others:无 //
/*****************************************************************/
void SendString(unsigned char *str)
{
while(*str!='\0')//当字符不为空时,继续发送
{
SendByte(*str++);//发送后指针str加1,指向下一个字节
}
}
/*****************************************************************
*@Function:Working //
*@Description: 对串口接收的数据进行处理 //
*@Input: 无//
*@Output:无 //
*@Return: 无 //
*@Others: 无 //
/*****************************************************************/
void Working()
{
if(command!=0x00)//如果command不为0x00(即接收到数据)
{
switch(command&0xf0)//对数据进行判断
{
case 0xa0://若为0xa0
P0=(P0|0x0f)&(~command|0xf0);//将command取反后取出后四位(将前四位置1),P0的低四位置1,两者与上,即保持P0的高四位,将command的低四位覆盖P0低四位
SelectHc573(4);//转换锁存器
command=0x00;//将command清零
break;
case 0xb0://若为0xb0
P0=(P0|0xf0)&(~command<<4|0x0f);//将command取反后左移四位,再取出前四位(将后四位置1),P0的前四位置1,两者与上,即保持P0的低四位,将command的高四位覆盖P0高四位
SelectHc573(4);//转换锁存器
command=0x00;//将command清零
break;
case 0xc0://若是0xc0
SendString("The system is runing\r\n");//发送字符串The system is runing\r\n
command=0x00;//将command清零
break;
}
}
}
/*****************************************************************
*@Function: InitSystem //
*@Description:初始化,关闭蜂鸣器,LED灯以及继电器 //
*@Input:无 //
*@Output:无 //
*@Return: 无 //
*@Others:无 //
/*****************************************************************/
void InitSystem()
{
SelectHc573(5);
P0=0x00;
SelectHc573(4);
P0=0xff;
}
void main()
{
InitSystem();
InitUart();
SendString("Welcom to FSZ system!\r\n");//发送字符串“Welcom to FSZ system!\r\n”
while(1)
{
Working();
}
}
蓝桥杯的学习笔记持续更新中~
要是文章有帮助的话,就点赞收藏关注一下啦!
感谢大家的观看
欢迎大家提出问题并指正~
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------