一.串口通信
1、全双工、半双工、单工
单工:只能一个人传输,只能向一个方向传输
半双工:只能一个人传输,可以多个方向传输
全双工:多方传输,多个方向传输
2、同步通信、一步通信
异步通信:双方时钟可以不同步,发送的信息封装(加上起始位、停止位)实现同步,效率低,用在低速传输中
同步通信:使用频率一致的时钟,数据帧通过独特的bit串作为启停标志,效率高,适合高速传输
3、波特率
数据传输速率使用波特率来表示,单位bps(bits per second)
串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信
单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力
硬件电路
简单双向串口通信有两根通信线(发送端TX和接收端RX)
TX与RX要交叉连接
当只需单向的数据传输时,可以只接一根通信线
当电平标准不一致时,需要加电平转换芯片
电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:
电平标准
TTL电平:+3.3V或+5V表示1,0V表示0
RS232电平:-3-15V表示1,+3+15V表示0
RS232是一种串行通信标准,全称为“推荐标准232”(Recommended Standard 232),由电子工业联盟(EIA)在1960年代制定。RS232广泛用于计算机和各种设备之间的串行数据传输,如调制解调器、打印机、扫描仪等。RS232定义了电气特性、信号功能、连接器类型和信号线的物理连接方式。
RS232的特点:
电气特性:RS232使用负逻辑电平,逻辑“1”通常表示为-3V到-15V之间的电压,而逻辑“0”表示为+3V到+15V之间的电压。这种电平标准允许在较长的电缆上进行可靠的数据传输。
信号线:RS232标准定义了多条信号线,包括发送数据(TXD)、接收数据(RXD)、请求发送(RTS)、清除发送(CTS)、数据终端就绪(DTR)、数据设备就绪(DSR)、数据设置就绪(DSR)、载波检测(DCD)等。
连接器:RS232标准最初使用DB-25连接器,后来随着设备的简化,DB-9连接器变得更为常见。DB-9连接器通常有9个引脚,而DB-25连接器有25个引脚。
通信模式:RS232支持全双工通信,即数据可以在两个方向上同时传输。
速率和距离:RS232标准支持的最高数据传输速率为20kbps(千比特每秒),在较低的数据速率下,传输距离可以达到15米以上。随着数据速率的提高,传输距离会相应减少。
RS232的应用:
RS232由于其简单性和可靠性,在许多应用中被广泛使用。例如:
计算机与外围设备:连接计算机与打印机、扫描仪等外围设备。
工业控制:用于工业设备之间的通信。
测试设备:连接测试仪器和计算机进行数据交换。
嵌入式系统:在嵌入式系统中,RS232常用于调试和数据传输。
RS232的局限性:
尽管RS232非常普及,但它也有一些局限性:
速率限制:随着数据传输需求的增加,RS232的速率限制成为了一个问题。
距离限制:在高速率下,RS232的传输距离受到限制。
电平差异:RS232的电平标准与现代电子设备常用的TTL电平不兼容,需要电平转换。
随着技术的发展,RS232逐渐被USB、RS485、以太网等更高速、更远距离的通信标准所取代。然而,由于其历史的普及性和设备的广泛存在,RS232在许多场合仍然被使用。
RS485电平:两线压差+2+6V表示1,-2-6V表示0(差分信号)
RS485是一种电气接口标准,用于实现多点通信网络中的串行数据传输。它由电子工业联盟(EIA)在1983年发布,是RS232的改进版,旨在提供更远距离和更高数据传输速率的通信能力。RS485广泛应用于工业自动化、楼宇自动化、电信、电力系统等领域。
RS485的特点:
差分信号:RS485使用差分信号传输,即使用两根线(A和B)来传输一个信号,其中A线传输正信号,B线传输负信号。这种设计可以有效抑制噪声干扰,提高信号的抗干扰能力。
多点通信:RS485支持多点通信,即一个主设备可以与多个从设备进行通信。这使得RS485非常适合于构建分布式控制系统。
较长的传输距离:RS485能够在较长距离上进行可靠的数据传输,通常在1200米范围内可以达到100kbps的数据速率。
较高的数据速率:RS485支持较高的数据速率,最高可达10Mbps,但实际应用中通常会根据传输距离和网络条件进行调整。
半双工通信:RS485通常工作在半双工模式下,即数据在同一时刻只能在一个方向上传输,但可以通过控制信号来切换发送和接收状态。
RS485的应用:
RS485由于其高可靠性和远距离传输能力,在许多领域得到了广泛应用:
工业自动化:用于连接PLC(可编程逻辑控制器)、传感器、执行器等设备。
楼宇自动化:用于智能建筑中的灯光控制、安全监控等系统。
电力系统:用于电力监控和控制设备之间的通信。
电信设备:用于远程通信设备之间的数据传输。
RS485的局限性:
尽管RS485具有许多优点,但它也有一些局限性:
半双工通信:RS485的半双工通信模式限制了数据传输的效率,特别是在需要同时进行双向通信的应用中。
复杂的网络设计:多点通信网络的设计和调试相对复杂,需要考虑终端匹配、信号反射等问题。
RS485作为一种成熟的技术,虽然在某些方面可能不如现代的通信标准(如以太网、CAN总线等)先进,但由于其稳定性和成本效益,它在许多应用中仍然是首选的通信方式。随着技术的发展,RS485也在不断地进行改进,以适应新的应用需求。
波特率:串口通信的速率
起始位:标志一个数据帧的开始,固定为低电平
数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行
校验位:用于数据验证,根据数据位计算得来
停止位:用于数据帧间隔,固定为高电平
波特率
发送器和接收器的波特率由波特率寄存器BRR里的DIV确定
计算公式:波特率 = fPCLK2/1 / (16 * DIV)
数据模式
HEX模式/十六进制模式/二进制模式:以原始数据的形式显示
文本模式/字符模式:以原始数据编码后的形式显示
serial.c
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
#include "Serial.h"
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Array);
}
}
void Serial_SendString(char *String)
{
uint8_t i;
for (i = 0; String != '\0'; i ++)
{
Serial_SendByte(String);
}
}
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y --)
{
Result *= X;
}
return Result;
}
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
}
}
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch);
return ch;
}
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}
uint8_t Serial_GetRxFlag(void)
{
if (Serial_RxFlag == 1)
{
Serial_RxFlag = 0;
return 1;
}
return 0;
}
uint8_t Serial_GetRxData(void)
{
return Serial_RxData;
}
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
Serial_RxData = USART_ReceiveData(USART1);
Serial_RxFlag = 1;
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
serial.h
#ifndef __SERIAL_H
#define __SERIAL_H
#include <stdio.h>
void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);
uint8_t Serial_GetRxFlag(void);
uint8_t Serial_GetRxData(void);
#endif
test.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Serial.h"
uint8_t RxData;
int main(void)
{
Serial_Init();
while (1)
{
if (Serial_GetRxFlag() == 1)
{
RxData = Serial_GetRxData();
Serial_SendByte(RxData);
OLED_ShowHexNum(1, 8, RxData, 2);
}
}
}
二.I2C通信
I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线
两根通信线:SCL(Serial Clock)、SDA(Serial Data)
同步,半双工
带数据应答
支持总线挂载多设备(一主多从、多主多从)
硬件电路
所有I2C设备的SCL连在一起,SDA连在一起
设备的SCL和SDA均要配置成开漏输出模式
SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右
起始条件:SCL高电平期间,SDA从高电平切换到低电平
终止条件:SCL高电平期间,SDA从低电平切换到高电平
发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
指定地址写
对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)
当前地址读
对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)
指定地址读
对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)
IIC总线连接多个器件:
每个器件都有自己固有的地址,只要发相应的地址就可以与之通讯
器件的地址请查器件手册 也可以找找例程。
对于不同地址的模块就不用多说了,直接分别对其地址进行通信即可。那么若拿到相同地址的模块,或者直接是相同的多个模块怎么办
方法一:(内置了两种地址的模块)
对于内置了两种地址的模块,可以通过对某个引脚置高或置低来选择其中一个地址,现假设置高为A,置低为B。
假设你有三个模块要同时通信,首先将模块1置高,模块2、模块3的地址选择口置低,这样仅有模块1在地址A,然后对地址A进行通信即可防止其他模块干扰。接下来将模块1置低,模块2置高,即可对模块2通信。循环下去即可实现同时对三个模块通信。
方法二:(具有使能端的模块)
若你手中的模块某个引脚必须拉低或拉高才能正常使用,那么仿照方法一,对其中一个使能,其他均处于非使能状态,如此便可以仅对其中一个模块通信咯。
万能方法三:(什么都没有,仅有一种地址的模块)
原本买来六个ADXL345来读取不同地方的加速度信息,datasheet里说可以通过对某个引脚置高置低来选择其中一个地址。然而发现并不能改变地址!于是只好想出这样一个邪恶的方法。
用到的工具是模拟开关,楼主以CD4053为例,这货非常便宜,几元钱可以买一大把。
简单来说模拟开关相当于多个单刀双掷开关,可以通过IO口输出高低电平控制某两路连通。
我们知道I2C通信有 SCL和SDA两根线,我们通过调整模拟开关使仅有一个模块完整接入I2C BUS即可实现只对其中一个通信。
三.SPI通信
SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线
四根通信线:SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select)
同步,全双工
支持总线挂载多设备(一主多从)
硬件电路
多路spi从设备连接方法
①GPIO模拟CS信号
②采用3 - 8译码器扩展8路SPI
所有SPI设备的SCK、MOSI、MISO分别连在一起
主机另外引出多条SS控制线,分别接到各从机的SS引脚
输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入
SPI时序基本单元
起始条件:SS从高电平切换到低电平
终止条件:SS从低电平切换到高电平
交换一个字节(模式0)
CPOL=0:空闲状态时,SCK为低电平
CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据
交换一个字节(模式1)
CPOL=0:空闲状态时,SCK为低电平
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据
交换一个字节(模式2)
CPOL=1:空闲状态时,SCK为高电平
CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据
交换一个字节(模式3)
CPOL=1:空闲状态时,SCK为高电平
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据
指定地址写
向SS指定的设备,发送写指令(0x02),
随后在指定地址(Address[23:0])下,写入指定数据(Data)
指定地址读
向SS指定的设备,发送读指令(0x03),
随后在指定地址(Address[23:0])下,读取从机数据(Data)
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_55389449/article/details/140180272
|