一、UART基础概念
UART(Universal Asynchronous Receiver/Transmitter) 通用异步收发器;
参与通信的设备称为主机;
通信的本质是信息的传达;
1.1 通信方式
1.2 串行通信与并行通信
- 并行通信:通信双方之间有两根及以上的数据线传输信息;传输速率较高,但会占用大量的芯片资源传输速率较高,但会占用大量的芯片资源.
- 串行通信:通信双方之间只有一根数据线传输信息;系统占用资源少,结构简单等优点。
USB(统一串口总线)
1.3 UART
UART(串口)是一种通信方式,全双工串行通信方式
作为常用的串行通信方式,以TTL为例,串口通信在不同主机之间的数据格式为:
1、空闲时数据线为高电平;
2、发送时发送一个低电平表示起始位;
3、发送的第一个比特是最低位(最右边)bit0即LBS;
4、校验位分为奇校验,偶校验和无校验。 (1)奇校验是指确保数据位加上校验位中"1",1的总数为奇数; (2) 偶校验是指确保数据位加上校验位中"1",1的总数为偶数;
5.为保证下一个字节发送前的起始位能够表现出来,校验位之后发送一个停止位1。(将数据分隔);
数据传输速率:
串行通信用波特率(bit per second)来描述数据传输的速率,记作bps。常见的波特率有1200、2400,4800,9600,115200等,表示每秒钟传输的比特数。
串行的异步通信与同步通信:
异步通信:指通信中两个字符(8位)之间的时间间隔是不固定的,而在一个字符内各位的时间间隔是固定的;
收发双方的波特率必须是事先约定好的;同步通信:要求发收双方具有同频同相的同步;
用专用时钟信号线来控制时钟的节奏,以为例:
- SDA(数据线)
- SCL(时钟线):用于同步双方时钟的节奏,一般由发送方决定;
主机间通信时的电器物理问题:
主机间通信无论采用并行还是串行方式,都无法避免一个物理现象:导线内阻不为零
造成的电压衰减。以之前讨论的TTL电平为例,主机之间的距离会造成高电平在接收端出现衰减现象和串扰(指不同信号之间相互干扰导致信号失真)影响。
1.TTL(Transistor-Transistor Logic)通常指的就是芯片引脚产生的电压,这个电压值跟选择的芯片有关,在51单片机系统下是5v;在2440下是3.3v等等。5vTTL通信距离通常被限制在10~20米之间,如果需要更远的距离,怎么解决呢?
2. 为解决这个问题IEEE(Institute of Electrical and Electronics Engineers)颁布了RS232标准,其中规定了:
逻辑高电平(逻辑1):在-3V到-15V之间
逻辑低电平(逻辑0):在+3V到+15V之间
收发主机间有三根线,分别是收、发和地,因此RS232是全双工的。理论上RS232能够传输20~30米。
3.同理RS485使用两根信号线(A和B)来传输数据,通过比较A和B之间的电压差来识别信息,电压范围分别为+7V到+12V和-7V到-12V。正电压表示高电平,负电压表示低电平。这种差分信号传输方式提高了抗干扰能力。RS485的传输距离可达1200米,适用于大范围的数据传输需求。由于采用的是压差,RS485在传输数据的某一时刻,两根线都要用到,所以它是半双工的。
二、串口通讯(51单片机——89C52)
硬件部分(USB下载电路)
Windows表示串口为COMn;
2.1 SBUF寄存器
2.2 SCON寄存器与PCON寄存器
STC89C51RC/RD+系列单片机的串行口设有两个控制寄存器:串行控制寄存器SCON和波特率选择特殊功能寄存器PCON
2.2.1 SCON寄存器
2.2.2 PCON寄存器
xdata 的作用:不将内容放在芯片内部的RAM中,放在扩展的RAM中
uart.c
#include "uart.h" #include <reg52.h> void init_uart(void) { //串口接收 SCON &= ~(3 << 6); SCON |= (1 << 6) | (1 << 4); //使参数生效 PCON &= ~(1 << 6); PCON |= (1 << 7); //设置波特率,51单片机使用定时器1 TMOD &= ~(0x0F << 4); TMOD |= (2 << 4); //TMOD |= (1 << 5);前者更有可读性 TL1 = 230; TH1 = 230; //打开定时器1 TCON |= (1 << 6); //打开中断控制位及串口控制位 IE |= (1 << 7) | (1 << 4); } //中断服务函数(TI RI都会导致中断) //1.void uart_handler(void) interrupt 4 //{ // if((SCON & (1 << 0)) == 1) // { // P2 = SBUF;//用LED显示 // SCON &= ~(1 << 0); // } //} //2. xdata char rcv_buffer[32]; unsigned int pos = 0; void uart_handler(void) interrupt 4 { if((SCON & (1 << 0)) == 1) { if(pos < 32) { rcv_buffer[pos++] = SBUF; rcv_buffer[pos] = 0; } SCON &= ~(1 << 0); } } //发送(轮询) void send_char(char ch) { SBUF = ch; while((SCON & (1 << 1)) == 0); SCON &= ~(1 << 1); } void send_buffer(const char *p, unsigned int len) { while(len--) { send_char(*p++); } } void send_str(const char *p) { while(*p) { send_char(*p++); } }
main.c
#include "uart.h" #include "delay.h" #include <reg52.h> #include <string.h> //int main(void) //{ // const char *s = "Hello World!"; // char buffer[] = {0xAA, 0xBB, 0x00, 0x11}; // init_uart(); // while(1) // { // //send_char('A'); // send_buffer(s,strlen(s)); // //send_buffer(buffer, sizeof(buffer) / sizeof(*buffer)); // delay(0xAFFF); // } //} //int main(void) //{ // init_uart(); // while(1) // { // if(pos != 0) // { // delay(0xAFFF); // send_buffer(rcv_buffer, pos); // pos = 0; // } // // } int main(void) { //xdata char buffer[16]; init_uart(); while(1) { if(pos != 0) { delay(0xAFFF); if(strcmp(rcv_buffer, "Hello") == 0) { send_str("Hi"); } else if(strcmp(rcv_buffer, "see u later") == 0) { send_str("bye"); } pos = 0; } } }
三、MODBUS通信协议
#include "uart.h"
#include "delay.h"
#include <string.h>
#include <stdio.h>
#include <reg52.h>
#include "led.h"
#include "digiter.h"
#include "timer.h"
#define DEV_ADDRESS 0x01
int parse(void)
{
int ret = 0;
if((unsigned char)rcv_buffer[0] == 0xAA && (unsigned char)rcv_buffer[6] == 0x0D)
{
P2 = 0;
if((unsigned char)rcv_buffer[1] == DEV_ADDRESS)
{
unsigned char sum = 0;
int i;
for(i = 0;i < 5;++i)
{
sum += (unsigned char)rcv_buffer[i];
}
if(sum == (unsigned char)rcv_buffer[5]) //判断校验码是否一致
{
ret = rcv_buffer[2]; //用于返回的功能码
}
}
}
return ret;
}
void do_something(int n)
{
switch(n)
{
case 1:
led_on(rcv_buffer[4]);
break;
case 2:
display(rcv_buffer[4]);
break;
case 3:
while(1)
{
init_timer0();
while(1)
{
}
}
break;
default:
break;
}
}
int main(void)
{
unsigned char sum1 = 0;
int t = 0;
init_uart();
while(1)
{
if(pos != 0)
{
int ret;
delay(0xAFFF);
ret = parse();
do_something(ret);
if(ret != 0)
{
xdata unsigned char buffer[10];
memcpy(buffer, rcv_buffer,7);
buffer[2] |= (1 << 7);
for(t = 0;t < 5;++t)
{
sum1 += (unsigned char)buffer[t];
}
if(buffer[5] == rcv_buffer[5])
{
buffer[5] = sum1;
send_buffer(buffer,7);
}
}
pos = 0;
}
}
}