什么是串行通信
- 通信分串行和并行:串行是指用一根线通信,并行是指用多根线同时通信。
- 这种通信也能够称为:串行通信、串口通信、UART、USART。
- 特点:异步、串行、全双工。
- 工作形式:有三根线(GND/RXD接管线/TXD发送线);数据在发送方和接管方的CPU中都是以字节为单位进行解决的;数据在通信线上以位为单位一一bit传输。
- 串行通信次要概念:起始位、数据位、奇偶效验位、进行位、波特率(一秒钟发送多少bit位,发送方和接管方波特率必须一样)
- 串行通信性能是SOC的一个外部外设提供的,与CPU自身无关。
STC51串行通信相干寄存器
管制寄存器PCON和SCON
串行管制寄存器SCON:串行管制寄存器SCON用于抉择串行通信的工作形式和某些管制性能。
SM0/FE:当PCON寄存器中的SMODO位为1时,该位用于帧谬误检测。当检测到一个有效进行位时,通过UART接收器设置该位。它必须由软件清零。当PCON寄存器中的SMODO位为0时,该位和SM1一起指定串行通信的工作形式(SM0、SM1)。
- 0 0 :工作形式0;同步移位串行形式;波特率是 SYSclk/12.
- 0 1 :工作形式1;8位UART,波特率可变;
- 1 0 :工作形式2;9位UART;
- 1 1 :工作形式3;9位UART;波特率可变;
- REN:容许/禁止串行接管管制位。(由软件置位和复位)
- TI:发送数据时的中断请求标记位。当发送完一帧数据后硬件主动置位,即TI=1。
- RI:接收数据时的中断请求标记位。当接管完一帧数据后硬件主动置位,即RI=1。
电源管制寄存器PCON:用于抉择波特率是否加倍
- SMOD:波特率抉择位。SMOD=1,加倍;SMOD=0,不加倍。
- SMOD0:帧谬误检测无效管制位。
中断容许寄存器IE
- EA : CPU的总中断容许管制位。
- ES:串行口中断容许位。
定时器/计数器管制寄存器TCON
- TR1:定时器T1的运行管制位。该位由软件置位和清零。
- TR1=1时开始计数,TR1=0时禁止计数。
串行口工作模式
次要利用串行口工作模式1:8位UART,波特率可变。
- 当软件设置SCON的SMO、SM1为“01”时,串行通信则以模式1工作。
- 一帧信息为10位:1位起始位,8位数据位(低位在先)和1位进行位。
- TXD为发送信息,RXD为接管信息。
- 一帧信息发送或接管实现后,就会发动中断请求,置位RI或TI。
波特率计算公式
- SMOD为0或1。
- SYSclk为零碎时钟频率。(我的是12MHz)
- TH1为主动重装载值。TH1取整数。
留神;计算波特率时,256-TH1的值必须要是整数左近零点零几的地位才行,差太多可能会造成乱码。(差了零点2都可能会乱码)
代码示例
串口初始化
// 串口初始化函数// 预设一个串口条件:8数据位、1进行位、0校验位、波特率9600// 初始化的次要工作就是去设置相干的寄存器void uart_init(void){ SCON = 0x50; // 01010000 串口工作在模式1(8位串口)、容许接管 PCON = 0x00; // 波特率不加倍 // 通信波特率相干的设置 TMOD = 0x20; // 用作定时器,设置T1为模式2(8位主动重装载) TH1 = 243; //2×12000000÷32÷12÷4800=13.0208,256-TH1=13,TH=243。 TL1 = 243; // 8位主动重装,当溢出时主动将TH1寄存的值装入TL1中。TH1和TL1必须雷同 TR1 = 1; // 开启T1定时/计数器 ES = 1; //串行口中断容许位 EA = 1; //总中断容许位}
发送数据
// 单片机通过串口发送1个字节到电脑端。void uart_send_byte(unsigned char c){ // 第1步,发送一个字节 SBUF = c; // 第2步,先确认串口发送局部没有在忙 while (!TI); // 第3步,软件复位TI标记位 TI = 0;}//单片机发送字符到电脑端void uart_send_string(unsigned char *str){ while (*str != '\0') { uart_send_byte(*str); // 发送1个字符 str++; // 指针指向下一个字符 }}//电脑端发送数据到单片机,单片机接收数据,触发中断,RI=1。void uart_isr(void) interrupt 4 using 1{ unsigned char tmp; if (RI) { tmp = SBUF; // 读取SBUF,其实就是读出了串口接管到的1字节 RI = 0; } uart_send_byte(tmp); //将接管到的数据再发送给电脑端,测试是否接管胜利。}
基于51单片机的I2C通信之EEPROM
基本知识
- ROM(只读存储器)、RAM(随机拜访存储器)、PROM(可编程ROM)
- EPROM(可擦除ROM)、EEPROM(电可擦除ROM)
- EEPROM在零碎中的存在模式:内置在单片机外部或内部扩大。
- EEPROM原理图:
I2C总线协定规定
- 任何将数据传输到总线的都作为发送器,任何从总线接收数据的器件都作为接收器。
- 数据传输由主器件管制,总线的串行时钟、起始进行条件均由主器件产生。
- 只有在总线非忙时才容许进行数据传输。
- 在数据传送时,过后钟线为高电平,数据线必须为固定状态,不容许有跳变。时钟线为高电平时,数据线的任何电平变动将被当作总线的启动或进行条件。
- 启动条件:启动条件必须在所以操作命令之前发送。时钟线放弃高电平期间,数据线电平从高到低的跳变作为I2C总线的启动信号。
- 进行条件:时钟线放弃高电平期间,数据线从低到高的跳变作为I2C总线的进行信号。操作完结时必须发送进行条件。
- I2C数据传输方式:
I2C总结
- 主CPU和其从属芯片最罕用的接口,尤其是各种传感器。
- 三根控制线:GND、SCL、SDA。串行、电平式。(STM32单片机中也是如此)
- 发送和接管字节时都是从高位开始。
- 总线式构造,能够一对多,总线上能够挂载上百个器件,用从地址来辨别。
- 主从式,由主设施发动通信及总线仲裁,从设施被动响应。
- 通信速率较低,不适宜语音、视频等。
I2C代码示例
/******************************************************************************** 函 数 名 : I2C_Start()* 函数性能 : 起始信号:在I2C_SCL时钟信号在高电平期间I2C_SDA信号产生一个降落沿* 输 入 : 无* 输 出 : 无* 备 注 : 起始之后I2C_SDA和I2C_SCL都为0*******************************************************************************/void I2C_Start(){ I2C_SDA = 1; I2C_Delay10us(); I2C_SCL = 1; I2C_Delay10us();//建设工夫是I2C_SDA放弃工夫>4.7us I2C_SDA = 0; I2C_Delay10us();//放弃工夫是>4us I2C_SCL = 0; I2C_Delay10us(); }/******************************************************************************** 函 数 名 : I2C_Stop()* 函数性能 : 终止信号:在I2C_SCL时钟信号高电平期间I2C_SDA信号产生一个回升沿* 输 入 : 无* 输 出 : 无* 备 注 : 完结之后放弃I2C_SDA和I2C_SCL都为1;示意总线闲暇*******************************************************************************/void I2C_Stop(){ I2C_SDA = 0; I2C_Delay10us(); I2C_SCL = 1; I2C_Delay10us();//建设工夫大于4.7us I2C_SDA = 1; I2C_Delay10us(); }/******************************************************************************** 函 数 名 : I2cSendByte(uchar num)* 函数性能 : 通过I2C发送一个字节。在I2C_SCL时钟信号高电平期间,* * 放弃发送信号I2C_SDA保持稳定* 输 入 : num ,ack* 输 出 : 0或1。发送胜利返回1,发送失败返回0* 备 注 : 发送完一个字节I2C_SCL=0, 须要应答则应答设置为1,否则为0*******************************************************************************/uchar I2C_SendByte(uchar dat, uchar ack){ uchar a = 0,b = 0;//最大255,一个机器周期为1us,最大延时255us。 // 为了保障时序正确,这里应该加一句 SCL = 0; for(a=0; a<8; a++)//要发送8位,从最高位开始 { I2C_SDA = dat >> 7; //起始信号之后I2C_SCL=0,所以能够间接扭转I2C_SDA信号 dat = dat << 1; I2C_Delay10us(); I2C_SCL = 1; I2C_Delay10us();//建设工夫>4.7us I2C_SCL = 0; I2C_Delay10us();//工夫大于4us } I2C_SDA = 1; // 主设施开释SDA线给从设施去操作 I2C_Delay10us(); I2C_SCL = 1; // 主设施开始了第9个周期 while(I2C_SDA && (ack == 1))//期待应答,也就是期待从设施把I2C_SDA拉低 { b++; if(b > 200) //如果超过200us没有应答发送失败,或者为非应答,示意接管完结 { I2C_SCL = 0; I2C_Delay10us(); return 0; } } I2C_SCL = 0; I2C_Delay10us(); return 1; }/******************************************************************************** 函 数 名 : I2cReadByte()* 函数性能 : 应用I2c读取一个字节* 输 入 : 无* 输 出 : dat* 备 注 : 接管完一个字节I2C_SCL=0*******************************************************************************/uchar I2C_ReadByte(){ uchar a = 0,dat = 0; I2C_SDA = 1; //CPU开释总线,让从设施接管。(51单片机中是这样解决,32中可能有点不同) I2C_Delay10us(); // 按情理这里应该有一个SCL = 0的 for(a=0; a<8; a++)//接管8个位 { I2C_SCL = 1; // 告诉从设施我要开始读了,能够放1bit数据到SDA了 I2C_Delay10us(); dat <<= 1; // 读取的时候是高位在前的 dat |= I2C_SDA; I2C_Delay10us(); I2C_SCL = 0; // 拉低,为下一个bit的周期做筹备 I2C_Delay10us(); } return dat; }
EEPROM(AT24C02芯片介绍(最多保留255个字节))
器件寻址
- 主器件通过发送一个起始信号启动发送过程,而后发送从器件地址。(从地址是芯片自身定义的)
- 8位从器件地址的高4位固定为1010,接下来的3位为从器件的地址位,最低位为从器件的读写位(1示意对从器件进行读操作,0示意对从器件进行写操作)
- 在主器件发送起始信号和从器件地址后,AT24C02会监督总线,当某一个器件的地址与发送的从地址雷同时,响应一个应答信号(通过SDA线)。
应答信号
- I2C总线数据传输时,每胜利传输一个字节数据后,接收器都必须产生一个应答信号,接收器在第九个时钟周期将SDA拉低,示意曾经收到一个字节数据。
- 当AT24C02工作于被读状态时,在发送一个字节之后会开释总线,并监督总线,如果接管到应答信号,则持续发送数据;若没有接管到应答信号,则进行发送数据。
- 写操作时序图)(ACK就是应答信号)
写操作
单写一个字节:
- 首先主器件发送起始命令和从器件地址信息。期待应答。
- 而后发送要写入数据的内存地址(即字节地址)。期待应答。
- 而后开始发送数据。期待应答。
- 最初发送进行信号。
- 代码示例
/******************************************************************************** 函 数 名 : void At24c02Write(unsigned char addr,unsigned char dat)* 函数性能 : 往24c02的一个地址写入一个数据* 输 入 : 无* 输 出 : 无*******************************************************************************/void At24c02Write(unsigned char addr,unsigned char dat){ I2C_Start(); I2C_SendByte(0xa0, 1);//发送从器件地址 I2C_SendByte(addr, 1);//发送要写入内存地址 I2C_SendByte(dat, 0); //发送数据 I2C_Stop();}
间断写入多个字节(AT24C01可一次写入8个字节,AT24C02/04/08/16可一次写入16个字节)
- 每发送一个字节数据后,AT24C芯片会产生一个应答并将字节地址低位加一,高位不变。
- 如果在发送进行信号之前,主器件发送的字节超出规定字节,则超出的字节将会笼罩先前写入的字节。
读操作
立即地址读:
- 如果上一次读/写操作的地址为N,则立刻读的地址从N+1开始。如果读数据时超过地址极限(AT04C02最多只能保留255字节),则会翻转到0地址持续读取。
选择性读:
- 选择性读操作容许主器件对寄存器的任意地址进行读操作。
- 读取过程:主器件首先通过发送起始信号和从器件地址以及想读取的字节数据地址执行一个伪写操作;在应答之后主器件从新发送起始信号和从器件地址,此时地址最初一地位一(进行读操作);AT24C02响应并发送应答信号,而后发送所须要的数据,主器件不发送应答信号但发送进行信号。
- 代码示例
/******************************************************************************** 函 数 名 : unsigned char At24c02Read(unsigned char addr)* 函数性能 : 读取24c02的一个地址的一个数据* 输 入 : 无* 输 出 : 无*******************************************************************************/unsigned char At24c02Read(unsigned char addr){ unsigned char num; I2C_Start(); I2C_SendByte(0xa0, 1); //发送从器件地址 I2C_SendByte(addr, 1); //发送要读取的地址 I2C_Start(); I2C_SendByte(0xa1, 1); //发送读器件地址 num=I2C_ReadByte(); //读取数据 I2C_Stop(); return num; }