通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系 统

通信协议:制定通信的规则,通信双方按照协议规则进行数据收发

USART通用同步异步收发器

USART介绍

USART是全双工异步/同步通信,一般为点对点通信,只有两个引脚RX和TX,其中RX是接收引脚,TX是发送引脚。

STM32F103C8T6 USART资源: USART1、 USART2、 USART3

全双工:是指可同时接收和发送数据。

半双工:是指能发送和接收,但是二者不能够同时接收和发送。

同步:通信双发按照一根时钟线约束通信。

异步:通信双方约定好通信速率。

USART优点

串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信

电平标准

电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:

TTL电平:+3.3V或+5V表示1,0V表示0

RS232电平:-3~-15V表示1,+3~+15V表示0

RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号) 

串口参数

波特率:串口通信的速率

起始位:标志一个数据帧的开始,固定为低电平

数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行

校验位:用于数据验证,根据数据位计算得来

停止位:用于数据帧间隔,固定为高电平

建议看一下手册25.3和25.6

USART基本配置

void Usart_Init()
{
	//时钟配置
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//外设端口初始化RX
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	//TX,复用由片上外设控制
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
	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(USART2,&USART_InitStructure);
	
	USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);//中断使能
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	

	USART_Cmd(USART2,ENABLE);
}



void USART2_IRQHandler(void)
{
	if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET)
	{
		RXTFLAG=USART_ReceiveData(USART2);
		
		USART_ClearITPendingBit(USART2,USART_IT_RXNE);
		 
	}
}

I2C总线(Inter IC BUS)

I2C介绍

两根通信线:SCL(Serial Clock)、SDA(Serial Data)

同步,半双工 带数据应答

支持总线挂载多设备(一主多从、多主多从)

设备的SCL和SDA均要配置成开漏输出模式

因为开漏模式下不仅可以输入也可以输出。

I 2 C主要特点可参考手册24.2

I 2 C主设备功能

 产生时钟

 产生起始和停止信号

支持不同的通讯速度

标准速度(高达100 kHz)

快速(高达400 kHz)

I2c功能

I 2 C模块接收和发送数据,并将数据从串行转换成并行,或并行转换成串行。

  1. 完整接收到一个字节(通常是 8 位)后,模块将字节从接收寄存器移到内部的数据缓冲区或内存中,这就是串行到并行的转换过程。

  2. 将这个字节逐位送到 SDA 线上,每次送出一位,同时生成相应的时钟信号(SCL)。这个过程就是并行到串行的转换,将并行数据(一个字节)转换成连续的位进行发送。

数据和地址按8位/字节进行传输,高位在前。

 

软件模拟I2c 通信

基本时序单元

发送一个字节

接受一个字节

 

应答位

 

 

void W_SDA(uint8_t BitValue) //Set Port Value
{	
 GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
	
}
void W_SCLK(uint8_t BitValue)	 //Set Port Value
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
}

uint8_t R_SDA() //Read Port Value
{
	return GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);

}
void i2_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}

void Start()
{
	W_SDA(1);//考虑到指定地址发或者读
	W_SCLK(1);
	W_SDA(0);
	W_SCLK(0);
}

void End()
{
	W_SDA(0);
	
	W_SCLK(1);
	W_SDA(1);
}

void SendByte(uint8_t Byte)
{
	uint8_t i;
	for(i=0;i<8;i++)
	{
		W_SDA(Byte&(0x80>>i));
		W_SCLK(1);
		W_SCLK(0);
	}
	
}
uint8_t ReciveByte()
{
	uint8_t i;
	uint8_t byte=0x80;
	for(i=0;i<8;i++)
	{
		W_SCLK(1);//高电平读取
		byte=((byte>>i)|(R_SDA()<<(8-i)));
		W_SCLK(0);
	}

}

硬件模拟I2C

STM32F103C8T6 I2C资源:I2C1,I2C2。

硬件使用I2C需要参考手册的I2C发送的时序

 

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//复用模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
	
	
	I2C_InitTypeDef I2c_InitStructure;
	I2c_InitStructure.I2C_Ack=I2C_Ack_Enable ;
	I2c_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;//应答 7 位地址
	I2c_InitStructure.I2C_ClockSpeed=40000;
	I2c_InitStructure.I2C_DutyCycle=I2C_DutyCycle_16_9;
	I2c_InitStructure.I2C_Mode=I2C_Mode_I2C;
	I2c_InitStructure.I2C_OwnAddress1=0x25;//作为从机才有用
	I2C_Init(I2C2,&I2c_InitStructure);
	
	I2C_Cmd(I2C2,ENABLE);

SPI(Serial Peripheral Interface)串行外设接口

是一种高速、全双工、同步的串行通信协议,用于短距离的设备间通信,常用于微控制器与各种外围设备(如传感器、闪存、实时钟等)之间。SPI 的主要特点是它采用主从架构,支持高数据传输速率,并且能够在多个设备之间进行通信。

SPI 主要信号线

  1. MOSI(Master Out Slave In):主设备输出,子设备输入的数据线。
  2. MISO(Master In Slave Out):主设备输入,子设备输出的数据线。
  3. SCK(Serial Clock):串行时钟,由主设备产生,用于同步数据传输。
  4. SS/CS(Slave Select/Chip Select):子设备选择信号,由主设备控制,用于选择要通信的子设备。当 SS 线为低电平时,子设备被选中并开始通信。

SPI 工作原理 

  1. 主从关系:在 SPI 通信中,有一个主设备(Master)和一个或多个从设备(Slave)。主设备控制时钟信号 (SCK) 和选择信号 (SS/CS),从设备根据这些信号响应主设备的请求。

  2. 同步通信:SPI 是同步通信协议,数据传输由时钟信号 (SCK) 同步。每个时钟周期都可以传输一位数据。

  3. 全双工通信:SPI 支持全双工通信,这意味着数据可以同时在 MOSI 和 MISO 线上传输,即在发送数据的同时也可以接收数据。

SPI四种传输模式

SPI_CR
寄存器的
CPOL

CPHA
位,能够组合成四种可能的时序关系。
CPOL(时钟极性)
位控制

没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果
CPOL


’0’

SCK
引脚在空闲状态保持低电平;如果
CPOL
被置
’1’

SCK
引脚在空闲状态保持高电平。

如果
CPHA(
时钟相位
)
位被置
’1’

SCK
时钟的第二个边沿
(CPOL
位为
0
时就是下降沿,
CPOL


’1’
时就是上升沿
)
进行数据位的采样,数据在第二个时钟边沿被锁存。如果
CPHA
位被清
’0’

SCK
时钟的第一边沿
(CPOL
位为’0’时就是上升沿,CPOL位为’1’时就是下降沿
)
进行数据位采

样,数据在第一个时钟边沿被锁存

数据传输过程

CS拉高选择从机,选择模式后,开始传输数据。其他的和i2c一样,不过SPI不需要应答。

 

软件模拟SPI

void Spi_W_SCL(uint8_t Bitvalue)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_5,Bitvalue);
}

void Spi_W_MOSI(uint8_t Bitvalue)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_7,Bitvalue);
}

void Spi_W_CS(uint8_t Bitvalue)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bitvalue);
}

uint8_t Spi_R_MISO()
{
	return GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6);
}
void Spi_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5|GPIO_Pin_7;
	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_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_SetBits(GPIOA,GPIO_Pin_4| GPIO_Pin_5|GPIO_Pin_7);
}
void Spi_Start()
{
	Spi_W_CS(1);
	Spi_W_CS(0);
	
}

void Spi_End()
{
	Spi_W_CS(1);
	
}

uint16_t  Spi_SwapByte(uint16_t Byte)//由于SPI内部移位寄存器是一位一位移动
{
	uint16_t i,temp=0x00;
	 
	for(i=0;i<8;i++)
	{
	Spi_W_MOSI(Byte&(0x80>>i));
	Spi_W_SCL(1);
	if(Spi_R_MISO()==1)temp|=(0x80>>i);
	Spi_W_SCL(0);
	}
	return temp;
	
}

硬件模拟SPI

stm32c8t6 SPI硬件资源:SPI1,SPI2

void Spi_W_CS(uint8_t Bitvalue)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bitvalue);
}
void Spi_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//外设spi没有专门设置测试引脚的函数
	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_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	
	SPI_InitTypeDef SPI_InitStructure;
	SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_16;
	SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;//数据捕获于第一个时钟沿;
	SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low;
	SPI_InitStructure.SPI_CRCPolynomial=10;
	SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;
	SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;// 数据传输从 MSB 位开始;高位先行
	SPI_InitStructure.SPI_Mode=SPI_Mode_Master;//主从模式
	SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;//内部 NSS 信号有 SSI 位控制
	SPI_Init(SPI1,&SPI_InitStructure);
	
	SPI_Cmd(SPI1,ENABLE);
	Spi_W_CS(0);
}
void Spi_Start()
{
	Spi_W_CS(1);
	Spi_W_CS(0);
	
}

作者:m0_69002246

物联沃分享整理
物联沃-IOTWORD物联网 » STM32常用通信协议汇总

发表回复