51单片机串口通信原理、相关寄存器配置与简单串口收发程序代码

目录

1. 串口通信原理

2. 51单片机串口通信

 2.1 串口简要模式图

 2.2 相关寄存器

(1)PCON、SCON、SBUF

(2)IE、IPH、IP

(3)配置T1定时器

2.3 波特率和系统时钟和TH1和TL1计算

 3.串口通信简单收发使用代码

 3.1 在STC-isp使用端口助手,从单片机发送字节

 3.2 通过端口助手利用主机输入数据在中断中控制LED

 3.3 利用中断把主机发送来数据发送回主机


1. 串口通信原理

        串口通信是通信设备间在一条传输线上串行逐个比特的发送数据的通信方式。串行通信又可分为同步异步两种通信方式。同步通信是在同一时钟信号控制下进行收发信号,异步通信中需要双方规定一致发送和接收频率

        数据传输的方向可分为单工只能向一个方向传输)半双工(不同时间在一根线上向不同方向传输)全双工(可同时向不同方向传输)。

图1.常见串行通信接口接口 

        UART是一种采用异步串行通信的通用异步收发器,在发送时将并行数据转换成串行数据,接收端则将串行数据转换成并行数据。此外UART一般需要两根数据,一根端口发送,一根端口接收。

 图2.硬件连接

        图3.一般协议层数据格式 

         常见串口通信速率为(9600、19200、38400、57600、115200)bps。

        UART串口物理层常用电平标准(51单片机使用TTL电平,由下不要直接将DB接口引线接到单片机会烧毁(15v > 5v)):

  • TTL电平:+5V 表示1,0V表示0
  • RS232电平(常用于DB 接口):-3~-15V表示1,+3~+15V表示0
  • RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)

2. 51单片机串口通信

图2.1.CPU线路图 

图2.2.USB转TTL 

  STC89C52rc有1个UART,有四种工作模式:(常用方式1)

 2.1 串口简要模式图

 图2.3 串口简要模式图

 图2.4 中断结构局部图

         SBUF为串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器,读操作时,读出的是接收寄存器。SMOD控制控制是否加倍速(置1相当于加倍)

 2.2 相关寄存器

(1)PCON、SCON、SBUF

        STC89C52RC及同系列单片机串行口设两个控制寄存器,串行控制寄存器SCON和 波特率选择特殊功能寄存器PCON

 PCON(不可位寻址):

SCON(可位寻址):


TI/RI为中断标志位,一般是当要发生中断事情发送才标志中断,所以一般初始化置0

由上,当我们 想要简单的在模式1下向主机发送数据:

SCON(SM0=0,SM1=1,SM2=0,REN=0/1,TB8=0,RB8=0,T1=0,R1=0)=> 0x40

且因为需要分频,需要波特率加倍,不然速率太低。

PCON(SM0D=1,SMOD0=0)  =>  PCON | 0x80

SBUF串行口缓冲寄存器:

        虽然地址相同,但SBUF是2个缓冲器,写SBUF的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。两个操作分别对应两个不同的寄存器,1个是只写寄存器,1个是只读寄存器

        软件操作上,我们可以只操作SBUF,要发送时,将要发送数据赋值给SBUF,同时注意在停止位发送后将TI复位。

(2)IE、IPH、IP

        与串行口中断相关的寄存器有IE和IPH、IP。

        串行口中断允许位ES位于中断允许寄存器IE中;串行口中断优先级控制位PS/PSH位于中断优先级控制寄存器IP/IPH中

IE(可位寻址):

 IP与PH(不可位寻址):

 为了简单,可以仅考虑两个优先级,只操作PS=0/1

当我们不需要中断操作,也可以不设置中断EA、ES

(3)配置T1定时器

        串行通信模式1的波特率是可变的,可变的波特由定时器/计数器T1独立波特率发生器
生 ,因此我们需要配置T1定时器,常选用定时器计数器T1的工作方式2(8位自动重装) 作为波特率的溢出率。

        对于TMOD,T1模式控制为前四位:(x,x,1,0)=> (TMOD & 0x0f) | 0x02

        对于TCNO模式1控制位:

                不需要计时器发送中断,只需要它的溢出:ET1 = 0;

                允许T1开始计时:TR1 = 1;

 (4)使用STC-ISP配置寄存器

  本系列单片机没有AUXR,系统时钟为11.0592MHZ(因为串口通信要求较精准,如果使用12mhz与板子晶振频率不符传输错误率较大,此外通信两端波特率也要一致

2.3 波特率和系统时钟和TH1和TL1计算

建议使用STC-ISP设置TH1和TL1

对于串口模式1,定时器1使用模式2(8位自动重装)。利用公式逆着推从溢出率推出波特率。

  1. 当TL1 = 0xf4
  2. (ff +1)- f4 = 12          //计数12次溢出
  3. 1 /(11.0592MHZ/12)= 1.0850694444444us    //定时器12分频下计数一次的时间
  4. 12*1.0850694444444us  = 13.0208333333328us
  5. 溢出率:1/13.0208333333328us = 0.07680000000000314572800000012885
  6.  波特率 = 2^1/32 * 溢出率 = 0.00480000000000019660800000000805HZ 约等于4800MHZ
  7. 误差 = (0.00480000000000019660800000000805-0.0048)/0.0048 约等于0

 3.串口通信简单收发使用代码

3.1 在STC-isp使用端口助手,从单片机发送字节

#include <REGX52.H>
void UartInit(void)		//4800bps@11.0592MHz
{
	PCON |= 0x80;		//使能波特率倍速位SMOD
	SCON  = 0x40;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF4;			//设置定时初始值
	TH1 = 0xF4;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
    
    //中断加不加都行,因为我们不需要中断操作
    //EA =1;
	//ES =1;
}

//发送一个字节数据经过SBUF缓存并到达主机
void UART_SendByte(unsigned char byte) {
	SBUF = byte;
    //当发送完成,TI位硬件自动置1
	while(TI == 0);
	TI = 0;
}

int main()
{
	UartInit();
	UART_SendByte(0x66);
	while(1)
	{

	}		
	
}

 3.2 通过端口助手利用主机输入数据在中断中控制LED

#include <REGX52.H>
void UartInit(void)		//4800bps@11.0592MHz
{
	PCON |= 0x80;		//使能波特率倍速位SMOD
	SCON  = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF4;			//设置定时初始值
	TH1 = 0xF4;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
    
    //我们尝试利用发送中断,所以需要中断操作,即电脑发送数据来,申请中断来接受数据和其他操作
    EA =1;
	ES =1;
    //为了简便,不配置优先级,选用默认优先级
}


int main()
{
	UartInit();
	while(1)
	{

	}		
	
}

void UART_Routine() interrupt 4 {
    //主机发送数据到SBUF后,RI会置1
    //单片机发送也会触发中断,为TI且占用同一中断,所以判断RI
    if(RI == 1)
    {
        //中断后响应的操作
        //利用主机发送给SBUF中数控制LED,如发送1就是除了LED1,其他都点亮
        P2 = SBUF;
        //RI必须软件复位
        RI = 0;
    }
    
}

 3.3 利用中断把主机发送来数据发送回主机

中断逻辑在注释中解释

#include <REGX52.H>
void UartInit(void)		//4800bps@11.0592MHz
{
	PCON |= 0x80;		//使能波特率倍速位SMOD
	SCON  = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF4;			//设置定时初始值
	TH1 = 0xF4;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
    
    //我们尝试利用发送中断,所以需要中断操作,即电脑发送数据来,申请中断来接受数据和其他操作
    EA =1;
	ES =1;
    //为了简便,不配置优先级,选用默认优先级
}

//发送一个字节数据经过SBUF缓存并到达主机
void UART_SendByte(unsigned char byte) {
	SBUF = byte;
    //当发送完成,TI位硬件自动置1
	while(TI == 0);
	TI = 0;
}

int main()
{
	UartInit();
	while(1)
	{

	}		
	
}

void UART_Routine() interrupt 4 {
    //主机发送数据到SBUF后,RI会置1
    //单片机发送也会触发中断,为TI且占用同一中断,所以判断RI
    if(RI == 1)
    {
        //中断后响应的操作
        //此时SBUF内容为主机发来的数据,通过UART_SendByte函数发送回到主机
        //因为该中断由接受端发起,发送操作已经中断,所以现在不会有接收操作与发送操作冲突
        UART_SendByte(SBUF);
        //RI必须软件复位
        RI = 0;
    }
    
}

  • 6
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Arduino和OpenMV之间进行串口通信时,你需要编写两端的代码。下面是一个示例,展示了如何在Arduino和OpenMV之间进行简单串口通信: Arduino端代码: ```cpp #include <SoftwareSerial.h> SoftwareSerial mySerial(2, 3); // 设置软串口引脚,这里使用2号引脚作为RX,3号引脚作为TX void setup() { Serial.begin(9600); // 初始化Arduino的硬串口 mySerial.begin(9600); // 初始化软串口 } void loop() { if (mySerial.available()) { char data = mySerial.read(); // 从软串口读取数据 Serial.print("Received data: "); Serial.println(data); // 打印接收到的数据到硬串口 } if (Serial.available()) { char data = Serial.read(); // 从硬串口读取数据 mySerial.print(data); // 发送数据到软串口 } } ``` OpenMV端代码: ```python import sensor, image, time, pyb uart = pyb.UART(3, 9600) # 初始化OpenMV的串口对象,使用波特率9600 while(True): if uart.any(): data = uart.readchar() # 从串口读取数据 print("Received data:", chr(data)) # 打印接收到的数据 if uart.write("Hello, World!") > 0: # 向串口发送数据 print("Data sent") time.sleep(100) ``` 在这个示例中,我们使用SoftwareSerial库在Arduino上创建了一个软串口对象,并初始化硬串口和软串口。在Arduino的`loop`函数中,我们检查软串口是否有可用的数据,如果有,我们从软串口读取数据并通过硬串口打印出来。同时,我们也检查硬串口是否有可用的数据,如果有,我们从硬串口读取数据并发送到软串口。 在OpenMV的代码中,我们使用pyb库初始化了一个UART对象,并设置波特率为9600。在一个无限循环中,我们检查串口是否有可用的数据,如果有,我们从串口读取数据并打印出来。同时,我们也向串口发送了一条数据。 请注意,具体的代码实现可能会因你所使用的Arduino型号和OpenMV型号而有所不同。此外,你还需要确保两端的波特率设置相同以确保正确的通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值