串口通信:波特率、软件使用与握手协议详解
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 进行通信,实现数据的交互。在实际应用中,可根据具体需求对代码和连接进行调整,以满足不同的通信要求。
超级会员免费看
2255

被折叠的 条评论
为什么被折叠?



