28、串口通信:波特率、软件使用与握手协议详解

串口通信:波特率、软件使用与握手协议详解

1. 波特率基础

在串行通信中,数据是逐位传输的,每秒能传输的比特数决定了系统的通信速度,这就是波特率。常见的波特率数值有:
- 110
- 300
- 600
- 1200
- 2400
- 4800
- 9600
- 14400
- 19200
- 38400
- 57600
- 115200
- 230400
- 460800
- 921600

大多数串行通信都需要设置波特率,PIC 芯片使用以下公式计算波特率:
[BaudRate = \frac{Fosc}{Mode \times (n + 1)}]
其中:
- (Fosc):振荡频率。
- (Mode):根据 BRG 和 ESUART 的模式设置,取值为 64、16 或 4。
- (n):取决于所需波特率的数值,存储在 BRGH 和 BRG 寄存器对中。

当已知所需波特率、振荡频率以及模式设置时,可将公式变形为求 (n) 的表达式:
[n = \frac{Fosc}{Mode \times BaudRate} - 1]

例如,若所需波特率为 9600,振荡频率为 8Mhz,模式数为 64(UART 工作在 8 位异步模式,BRGH 和 BRG16 均设为逻辑‘0’),代入公式可得:
[n = \frac{8000000}{64 \times 9600} - 1 \approx 12.0208]
由于 (n) 需为整数,故取 (n = 12)。此时,SPBRGH 存储 0((n) 的高字节),SPBRG 存储 12(十进制)。

UART 的设置如下表所示:
|配置位|BRGH(TXSTA 的第 2 位)|BRG 模式|ESUART 模式|波特率公式|SYNC|BRG16(BAUDCON 的第 3 位)|
| ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|0|0|0|8 位|异步|( \frac{Fosc}{n + 16} )|0|
|0|0|1|8 位|异步|( \frac{Fosc}{n + 16} )|0|
|0|1|0|16 位|异步|( \frac{Fosc}{n + 4} )|0|
|0|1|1|16 位|异步|( \frac{Fosc}{n + 4} )|0|
|1|0|x|8 位|同步|( \frac{Fosc}{n + 64} )|x|
|1|1|x|16 位|同步|( \frac{Fosc}{n + 64} )|x|

2. 使用 Tera Term 软件

Tera Term 是一款免费软件,可将 PC 用作终端来发送和接收数据。使用该软件时,若笔记本无串行通信端口,可使用 Moyina USB 转串口转换器连接 PIC。具体操作步骤如下:
1. 点击 Tera Term 图标,软件启动并显示初始界面。
2. 点击初始界面中的串行选项,软件会自动查找 USB 转换器连接的正确通信端口。若未找到或找错,需使用设备管理器查找。
3. 选择正确的串行通信端口并点击“确定”,将显示主终端屏幕。

在主终端屏幕中,可通过主菜单栏的“设置”选项选择串行端口,设置其他参数:
- 速度 :设置所需的波特率,常见为 9600。
- 数据 :设置数据传输的位数,通常为 8 位。
- 奇偶校验 :用于检查发送和接收的数据是否一致,可选择“无”、“奇”、“偶”、“标记”、“空格”。此处选择“无”。
- 停止位 :设置停止位的数量,可选 1、1.5 或 2,此处选择 1 位。
- 流控制 :确保数据安全传输,避免冲突,可选“无”、“Xon/Xoff 软件控制”、“RTS/CTS(硬件控制)”、“DSR/DTR(硬件控制)”,此处选择“无”。

此外,还可设置终端窗口的参数,如终端大小、换行符等。

3. 使用握手协议

在通信过程中,可能会出现 PIC 向终端写入数据时终端未准备好,或终端向 PIC 写入数据时出现冲突的情况。为避免此类问题,可使用握手协议,即终端和 PIC 相互发送信号,表明可以发送(CTS)和准备发送(RTS)。

以下是使用握手协议的代码示例:

/*This is a basic program to control the LCD and the 
UART using the PIC 18F4525
Written by H H Ward dated 02/04/16.
*  modified 24/06/16 to include running from an interrupt 
whilst main program is simply flashing an led
*  the ISR sends out the character received at the uart 
back to a terminal and then sends the numbers 0 to 9
*  inserting a line after each number has been sent to 
the terminal.
*  The program also echos the character received onto 
the LCD connected to the pic.
*  Note the program has the addition of handshaking 
using the CTS and RTS signals.
*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <4bitLCDPortb.h>
//some definitions
#define RTS PORTDbits.RD0
#define CTS PORTDbits.RD1
//some variables
unsigned char n, count, newdatain = 0;
//the subroutines
void shortdelay ()
{
    TMR0 = 0;
    while (TMR0 < 255);
}
void delay (unsigned char t)
{
    for (n = 0; n < t; n ++)
    {
        TMR0 = 0;
        while (TMR0 < 255);
    }
}
void sendDeviceChar(char byte)
{
    TXREG = byte;
    while(!TXIF);
    while(!TRMT);
    shortdelay ();
}
void sendDeviceString(const char* meshw)
{
    RTS = 1;
    while(*meshw)
    {
        while(!TXIF);
        TXREG = (*meshw++);
        shortdelay ();
    }
}
void interrupt  isr1 ()
{
    if (PIR1bits.RCIF == 1)
    {
        RTS = 1;
        PIR1bits.RCIF = 0;
        if(OERR)
        {
            CREN = 0;
            CREN = 1;
        }
        while(!RCIF);
        newdatain = RCREG;
        lcdData = newdatain;
        lcdOut ();
        PORTA = newdatain;
        while (CTS);
        TXREG = newdatain;
        shortdelay ();
        TXREG = 0x0a;
        shortdelay ();
        for (n = 0x30; n < 0x3A; n++)
        {
            TXREG = 0X0A;
            shortdelay ();
            TXREG = 0x0D;
            shortdelay ();
            TXREG = n;
            shortdelay ();
            TXREG = 0x0A;
        }
        RTS = 0;
    }
}
void main ()
{
    PORTA = 0;
    PORTB = 0;
    PORTC = 0;
    PORTD = 0;
    TRISA = 0X00;
    TRISB = 0x00;
    TRISC = 0b10000000;
    TRISD = 0b00000010;
    ADCON0 = 0x00;
    ADCON1 = 0x0F;
    OSCTUNE = 0b10000000;
    OSCCON = 0b01110000;
    T0CON = 0b11000111;
    INTCON = 0b11000000;
    PIE1bits.RC1IE = 1;
    TXSTA = 0b00100000;
    RCSTA = 0b10010000;
    BAUDCON = 0b00000000;
    SPBRG = 12;
    setUpTheLCD ();
    clearTheScreen ();
    writeString ("Coded Handshaking");
    sendDeviceString ("Coded Handshaking Working Now");
    sendDeviceChar (0X0A);
    sendDeviceChar (0X0D);
    line2 ();
    while (1)
    {
        RTS = 0;
        PORTDbits.RD3 = PORTDbits.RD3^1;
        delay (20);
    }
}

代码分析

  • 定义 RTS 和 CTS 引脚 :将 PORTD 的第 0 位定义为 RTS 引脚,第 1 位定义为 CTS 引脚。
  • 发送字符串 :调用 sendDeviceString 函数时,先将 RTS 置为 1,表示 PIC 未准备好接收终端数据,然后逐字符发送字符串,发送完成后将 RTS 置为 0。
  • 中断处理 :当终端向 PIC 发送数据时,UART 产生中断,进入中断服务程序。在中断服务程序中,先将 RTS 置为 1,处理接收到的数据,发送数字 0 - 9,最后将 RTS 置为 0。
  • 主循环 :在主循环中,将 RTS 置为 0,允许终端发送数据,同时使连接到 PORTD 第 3 位的 LED 闪烁。

以下是该程序的流程图:

graph TD;
    A[开始] --> B[初始化端口和寄存器];
    B --> C[设置 LCD];
    C --> D[显示信息到 LCD 和终端];
    D --> E[进入主循环];
    E --> F[RTS = 0];
    F --> G[LED 闪烁];
    G --> H[延迟];
    H --> E;
    I[终端发送数据] --> J[UART 中断];
    J --> K[RTS = 1];
    K --> L[处理数据];
    L --> M[发送数字 0 - 9];
    M --> N[RTS = 0];
    N --> E;

通过以上步骤和代码,可实现基于握手协议的 UART 通信,确保数据的安全传输。

4. 两台 PIC 通过 UART 通信

在这个实践中,我们要对两台 PIC 进行编程,使其通过 UART 相互通信。一台称为 PIC1,另一台称为 PIC2。PIC1 使用矩阵板,LCD 连接到 PORTB,使用头文件 4bitLCDPortb.h ;PIC2 使用 Microchip 演示板,LCD 连接到 PORTD,使用头文件 4bitLCDDemoBoard.h 。因此,TRIS 寄存器会有一些小差异。此外,PIC1 的 RTS 连接到 PORTD 的第 0 位,CTS 连接到第 1 位;PIC2 的 RTS 连接到 PORTB 的第 0 位,CTS 连接到第 1 位。并且,PIC1 的 RTS 连接到 PIC2 的 CTS,PIC1 的 CTS 连接到 PIC2 的 RTS;PIC1 的 TXD 连接到 PIC2 的 RXD,PIC1 的 RXD 连接到 PIC2 的 TXD。

PIC1 的代码

/*This is a basic program to use the UART
To communicate with two PICs
This is the program for PIC one
Written by H H Ward for the PIC18F4525
Dated 03/04/2021*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <4bitLCDPortb.h>
unsigned char n, count, newdatain = 0;
unsigned char mess[30], *messpointer;
#define repeatButton PORTAbits.RA4
#define RTS PORTDbits.RD0
#define CTS PORTDbits.RD1
void shortdelay ()
{
    TMR0 = 0;
    while (TMR0 < 255);
}
void delay (unsigned char t)
{
    for (n = 0; n < t; n ++)
    {
        TMR0 = 0;
        while (TMR0 < 255);
    }
}
void sendDeviceString(const char* meshw)
{
    while(*meshw)
    {
        while (CTS);
        RTS = 1;
        while(!TXIF);
        TXREG = (*meshw++);
        shortdelay ();
        RTS = 0;
    }
}
void interrupt  isr1 ()
{
    if (PIR1bits.RCIF == 1)
    {
        RTS = 1;
        do
        {
            if(OERR)
            {
                CREN = 0;
                CREN = 1;
            }
            while(!RCIF);
            newdatain = RCREG;
            lcdData = newdatain;
            lcdOut ();
            shortdelay ();
        }while (RCIF);
        RTS = 0;
    }
}
void main ()
{
    PORTA = 0;
    PORTB = 0;
    PORTC = 0;
    PORTD = 0;
    TRISA = 0b00010000;
    TRISB = 0x00;
    TRISC = 0b10000000;
    TRISD = 0x02;
    ADCON0 = 0x00;
    ADCON1 = 0x0F;
    OSCCON = 0b01110000;
    OSCTUNE = 0b10000000;
    T0CON = 0b11000111;
    INTCON = 0b11000000;
    PIE1bits.RC1IE = 1;
    TXSTA = 0b00100000;
    RCSTA = 0b10010000;
    BAUDCON = 0b00000000;
    SPBRG = 12;
    messpointer = mess;
    setUpTheLCD ();
    clearTheScreen ();
    writeString ("Coded PIC1");
    line2 ();
    while (1)
    {
        while (!repeatButton);
        while (CTS);
        sendDeviceString ("Hi");
        delay (10);
        while (!repeatButton);
        while (CTS);
        sendDeviceString ("Good work");
        delay (10);
        while (!repeatButton);
        delay (10);
    }
}

代码分析

  • 定义部分 :定义了重复按钮、RTS 和 CTS 引脚,以及一些变量和指针。
  • 延时函数 shortdelay delay 函数用于产生延时。
  • 发送字符串函数 sendDeviceString 函数在发送字符串时,会先检查 CTS 信号,将 RTS 置为 1 表示正在发送,发送一个字符后将 RTS 置为 0。
  • 中断服务函数 :当接收到数据时,进入中断服务函数,处理可能的错误,将接收到的数据显示在 LCD 上。
  • 主函数 :初始化端口和寄存器,设置 LCD,显示信息,然后进入主循环。在主循环中,当按下重复按钮时,发送“Hi”和“Good work”消息。

以下是 PIC1 程序的流程图:

graph TD;
    A[开始] --> B[初始化端口和寄存器];
    B --> C[设置 LCD];
    C --> D[显示信息到 LCD];
    D --> E[进入主循环];
    E --> F[等待重复按钮按下];
    F --> G[等待 CTS 信号];
    G --> H[发送 "Hi"];
    H --> I[延迟];
    I --> J[等待重复按钮按下];
    J --> K[等待 CTS 信号];
    K --> L[发送 "Good work"];
    L --> M[延迟];
    M --> N[等待重复按钮按下];
    N --> O[延迟];
    O --> E;
    P[接收到数据] --> Q[UART 中断];
    Q --> R[RTS = 1];
    R --> S[处理数据];
    S --> T[RTS = 0];
    T --> E;

连接关系总结

设备 连接说明
PIC1 - RTS 连接到 PORTD 的第 0 位
- CTS 连接到 PORTD 的第 1 位
- TXD 连接到 PIC2 的 RXD
- RXD 连接到 PIC2 的 TXD
PIC2 - RTS 连接到 PORTB 的第 0 位
- CTS 连接到 PORTB 的第 1 位

通过以上代码和连接方式,两台 PIC 可以通过 UART 进行通信,实现数据的交互。在实际应用中,可根据具体需求对代码和连接进行调整,以满足不同的通信要求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值