stm32上常用的几个通信协议简介及相关代码

USART

USART是一个全双工通用同步/异步串行收发模块,该接口是一个高度灵活的串行通信设备特点如下:

1. 全双工操作(相互独立的接收数据和发送数据);

2. 同步操作时,可主机时钟同步,也可从机时钟同步;

3. 独立的高精度波特率发生器,不占用定时/计数器;

4. 支持5、6、7、8和9位数据位,1或2位停止位的串行数据帧结构;

5. 由硬件支持的奇偶校验位发生和检验;

6. 数据溢出检测;

7. 帧错误检测;

8. 包括错误起始位的检测噪声滤波器和数字低通滤波器;

9. 三个完全独立的中断,TX发送完成、TX发送数据寄存器空、RX接收完成;

10.支持多机通信模式;

11.支持倍速异步通信模式。

传输协议:

stm32常用代码

									USART初始化结构体
									
typedef struct {
 uint32_t USART_BaudRate; // 波特率
 uint16_t USART_WordLength; // 字长
 uint16_t USART_StopBits; // 停止位
 uint16_t USART_Parity; // 校验位
 uint16_t USART_Mode; // USART 模式
 uint16_t USART_HardwareFlowControl; // 硬件流控制
 } USART_InitTypeDef;
void USART_Init(u32 bound)

{ 

GPIO_InitTypeDef GPIO_InitStructure; 

USART_InitTypeDef USART_InitStructure; 

NVIC_InitTypeDef NVIC_InitStructure; 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1和GPIOA时钟 

USART_DeInit(USART1); //复位串口1(各参数置为缺省值) 



//USART1_TX(发送数据) PA.9引脚 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 

GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA.9 



//USART1_RX(接收数据) PA.10引脚 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 

GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA.10 



//NVIC中断向量配置  

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; 

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级置为3 

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级置为3,优先级依据不同的中断重要性不同来确定。 

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 

NVIC_Init(&NVIC_InitStructure); //根据上面设置的参数初始化NVIC寄存器 



//USART初始化设置 

USART_InitStructure.USART_BaudRate = bound;//波特率为9600; 

USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据 

USART_InitStructure.USART_StopBits = USART_StopBits_1;//1个停止位 

USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位 

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制 

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 



USART_Init(USART1, &USART_InitStructure); //串口初始化 

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//中断开启 

USART_Cmd(USART1, ENABLE); //串口使能

}
/***************** 发送一个字符 **********************/
 void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
 {
 /* 发送一个字节数据到 USART */
 USART_SendData(pUSARTx,ch);
 
 /* 等待发送数据寄存器为空 */
 while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
 }
 
 /***************** 发送字符串 **********************/
 void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
 {
 unsigned int k=0;
 do {
 Usart_SendByte( pUSARTx, *(str + k) );
 k++;
 } while (*(str + k)!='\0');
 
 /* 等待发送完成 */
 while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) {
 }
 }
void DEBUG_USART_IRQHandler(void)
 {
 uint8_t ucTemp;
 if (USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET) 
 {
 ucTemp = USART_ReceiveData( DEBUG_USARTx );
 USART_SendData(USARTx,ucTemp);
 }
 
 }
int main(void)
 {
 /*初始化 USART 配置模式为 115200 8-N-1,中断接收*/
 USART_Init();
 
 Usart_SendString( DEBUG_USARTx,"这是一个串口中断接收回显实验\n");
 
 while (1) {
 
 }
 }

I2C

        I2C 通讯协议(Inter-Integrated Circuit)是由 Phiilps 公司开发的,由于它引脚少,硬件实 现简单,可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备,现在被广泛地 使用在系统内多个集成电路(IC)间的通讯。 IIC协议可以分为物理层和协议层。

 

    I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。

通信格式:

 

 stm32常用代码

void I2C1_GPIO_Configuration(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//必须设置为开漏输出,实现iic的线与逻辑
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_PuPd =   GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1); 
    GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);
}
void I2C1_Configuration(void)
{
    I2C_InitTypeDef I2C_InitStructure;

    I2C_DeInit(I2C1);
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0XA0;//主机的地址        
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 100000;//100KHZ
    I2C_Init(I2C1, &I2C_InitStructure);
    I2C_Cmd(I2C1, ENABLE);                                             
}

 

void I2C1_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);   
    I2C1_GPIO_Configuration();
    I2C1_Configuration();
}

写数据

uint8_t I2C_Master_BufferWrite(I2C_TypeDef * I2Cx, uint8_t* pBuffer, uint32_t NumByteToWrite, uint8_t SlaveAddress)
{
    if(NumByteToWrite==0)
        return 1;
    /* 1.开始*/
    I2C_GenerateSTART(I2Cx, ENABLE);
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

    /* 2.设备地址·/写 */
    I2C_Send7bitAddress(I2Cx, SlaveAddress, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    /* 3.连续写数据 */
    while(NumByteToWrite--)
    {
      I2C_SendData(I2Cx, *pBuffer);
      while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
      pBuffer++;
    }

    /* 4.停止 */
    I2C_GenerateSTOP(I2Cx, ENABLE);
    while ((I2Cx->CR1&0x200) == 0x200);
    return 0;
}

读数据

uint8_t I2C_Master_BufferRead(I2C_TypeDef * I2Cx, uint8_t* pBuffer, uint32_t NumByteToRead, uint8_t SlaveAddress)
{
    if(NumByteToRead==0)
        return 1;

    while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));  
    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    /* 1.开始*/
    I2C_GenerateSTART(I2Cx, ENABLE);
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
    /* 2.设备地址·/写 */
    I2C_Send7bitAddress(I2Cx, SlaveAddress, I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    /* 3.开始*/
    I2C_GenerateSTART(I2Cx, ENABLE);
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
    /* 4.设备地址·/读 */
    I2C_Send7bitAddress(I2Cx, SlaveAddress, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

    /* 5.连续写数据 */
    while (NumByteToRead)
    {
        if(NumByteToRead==1)
        {
            I2C_AcknowledgeConfig(I2Cx, DISABLE);
            I2C_GenerateSTOP(I2Cx, ENABLE);//6.停止,非应答
        }

        while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED));  /* EV7 */
        *pBuffer++ = I2C_ReceiveData(I2Cx);
        NumByteToRead--;
    }

    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    return 0;
}   

RS-232通讯协议
  RS-232是美国电子工业协会EIA(ElectronicIndustry Association)制定的一种串行物理接口标准。RS是英文“推荐标准”的缩写,232为标识号通常。RS-232 接口以9个引脚 (DB-9) 或是25个引脚(DB-25) 的型态出现,一般个人计算机上会有两组RS-232 接口,分别称为 COM1 和 COM2 。

        RS-232总线规定了25条线,包含了两个信号通道,即第一通道(称为主通道)和第二通道(称为副通道)。利用RS- 232总线可以实现全双工通信,通常使用的是主通道,而副通道使用较少。在一般应用中,使用3条~9条信号线就可以实现全双工通信,采用三条信号线(接收线、发送线和信号线)能实现简单的全双工通信过程。

        RS-232规定的标准传送速率有50b/s、75b/s、110b/s、150b/s、300b/s、600b/s、1200b/s、2400b/s、4800b/s、9600b/s、19200b/s,可以灵活地适应不同速率的设备。对于慢速外设,可以选择较低的传送速率:反之,可以选择较高的传送速率。

采用负逻辑传送

规定逻辑“1”的电平为-5V~-15 V,逻辑“0”的电平为+5 V~+15 V。选用该电气标准的目的在于提高抗干扰能力,增大通信距离。RS -232的噪声容限为2V,接收器将能识别高至+3V的信号作为逻辑“0”,将低到-3 V的信号作为逻辑“1”。 

传送距离较远

由于RS -232采用串行传送方式,并且将微机的TTL电平转换为RS-232C电平,其传送距离一般可达30 m。若采用光电隔离20 mA的电流环进行传送,其传送距离可以达到1000 m。另外,如果在RS-232总线接口再加上Modem,通过有线、无线或光纤进行传送,其传输距离可以更远。

RS232C标准接口有25根线,常用的只有9根,它们是:

(1)接收线信号检出( Received Line Signal Detection,RSD)——用来表示DCE已接通通信链路,告知DTE准备接收数据。此线也叫作数据载波检出(Data Carrier detection,DCD)线。 

(2)接收数据( Received data,RXD)——通过RXD线终端接收从 MODEM发来的串行数据(DCE→DTE)。 

(3)发送数据( Transmitted data,TXD)——通过TXD终端将串行数据发送到 MODEM(DTE→DCE)。 

(4)数据终端准备好( Data Terminal Ready,DTR)——有效时(ON)状态,表明数据终端可以使用。 

(5)地线-GND。 

(6)数据装置准备好( Data Set ready,DSR)——有效时(ON)状态,表明通信装置处于可以使用的状态。 

(7)请求发送( Request to Send)——用来表示DTE请求DCE发送数据,即当终端要发送数据时,使该信号有效(ON状态),向 MODEM请求发送。它用来控制 MODEM是否要进入发送状态。 [3] 

(8)清除发送( Clear to Send,CTS)―用来表示DCE准备好接收DTE发来的数据,是对请求发送信号RTS的响应信号。当 MODEM已准备好接收终端传来的数据并向前发送时,使该信号有效,通知终端开始沿发送数据线TXD发送数据。 

(9)振铃指示( Ringing,R)——当 MODEM收到交换台送来的振铃呼叫信号时,使该信号有效(ON状态),通知终端,已被呼叫。 

SPI通信

        SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

SPI接口一般使用四条信号线通信:
SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)

MISO: 该引脚在从模式下发送数据,在主模式下接收数据。
MOSI: 该引脚在主模式下发送数据,在从模式下接收数据。
SCLK:串行时钟信号,由主设备产生。
CS/SS:从设备片选信号,由主设备控制避免数据线上的冲突。

 

SPI通信有4种不同的操作模式,不同的从设备可能在出厂是就是配置为某种模式,这是不能改变的;但我们的通信双方必须是工作在同一模式下,所以我们可以对我们的主设备的SPI模式进行配置,通过CPOL(时钟极性)和CPHA(时钟相位)来
控制我们主设备的通信模式,具体如下:

时钟极性(CPOL)定义了时钟空闲状态电平:

CPOL=0,表示当SCLK=0时处于空闲态,所以有效状态就是SCLK处于高电平时
CPOL=1,表示当SCLK=1时处于空闲态,所以有效状态就是SCLK处于低电平时


时钟相位(CPHA)定义数据的采集时间。

CPHA=0,在时钟的第一个跳变沿(上升沿或下降沿)进行数据采样,在第2个边沿发送数据
CPHA=1,在时钟的第二个跳变沿(上升沿或下降沿)进行数据采样,在第1个边沿发送数据

stm32常用程序

typedef struct
{
uint16_t SPI_Direction; /*!< 传输方向,两向全双工,单向接收等*/
uint16_t SPI_Mode; /*!< 模式选择,确定主机还是从机 */
uint16_t SPI_DataSize; /*!< 数据大小,8位还是16位 */
uint16_t SPI_CPOL; /*!< 时钟极性选择 */
uint16_t SPI_CPHA; /*!< 时钟相位选择 */
uint16_t SPI_NSS; /*!< 片选是硬件还是软件*/
uint16_t SPI_BaudRatePrescaler; /*!< 分频系数 */
uint16_t SPI_FirstBit; /*!< 指定数据传输是从MSB还是LSB位开始的。M
SB就是二进制第一位,LSB就是最后一位 */
uint16_t SPI_CRCPolynomial; /*!< CRC校验 ,设置 CRC 校验多项式,提高通
信可靠性,大于 1 即可*/
}SPI_InitTypeDef;

void SPI2_Init(void)
{
 	GPIO_InitTypeDef GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;
 
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能 
	RCC_APB1PeriphClockCmd(	RCC_APB1Periph_SPI2,  ENABLE );//SPI2时钟使能 	
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
 
 	GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);  //PB13/14/15上拉
 
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步时钟的空闲状态为高电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第二个跳变沿(上升或下降)数据被采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//定义波特率预分频的值:波特率预分频值为256
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
	SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
 
	SPI_Cmd(SPI2, ENABLE); //使能SPI外设
	
	SPI2_ReadWriteByte(0xff);//启动传输		 

} 

标准库:
u8 SPIx_ReadWriteByte(u8 TxData)
{
    u8 retry=0;
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
    {
    }//等待发送区空
    SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个byte 数据
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
    {
    } //等待接收完一个byte
    return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}
 
HLA库:
uint8_t SPI_SendByte(uint8_t byte)
{
    uint8_t d_read,d_send=byte;
    if(HAL_SPI_TransmitReceive(&hspi1,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK)
    d_read=0XFF;
    return d_read;


 CAN总线

        CAN 总线使用串行数据传输方式,且总线协议支持多主控制器。当CAN 总线上的一个节点(站)发送数据时,它以报文形式广播给网络中所有节点。

        每组报文开头的11位字符为标识符,定义了报文的优先级,这种报文格式称为面向内容的编址方案。在同一系统中标识符是唯一的,不可能有两个站发送具有相同标识符的报文。当几个站同时竞争总线读取时,这种配置十分重要。

 

CAN总线使用双绞线进行差分电压传输,两条信号线被称为CAN高(CAN_H)和CAN_L)。

两条线静态时均为2.5V左右,此时状态表示为逻辑1,也被称作隐性。当两条线电压值出现差异时,通常CAN_H=3.5V和CAN_L=1.5V,此时状态表示为逻辑0,也称作显性。即:

差分电压CAN_diff = 0V,表示逻辑“1”,为隐性

差分电压CAN_diff = 2V,表示逻辑“0”,为显性

#include "pbdata.h"

void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void CAN_Configuration(void);


int main(void)
{
	CanTxMsg TxMessage;
	
	RCC_Configuration();	//时钟配置
	GPIO_Configuration();//端口配置
	NVIC_Configuration();
	CAN_Configuration();
	
	
	while(1)
	{
		//每隔1s发送一个报文,一个报文8B
		TxMessage.StdId=0xFF00>>5;//标准帧只有31-21位,对于16位寄存器而言,低五位为扩展帧,所以在写16位数据时,最后5位置0
		TxMessage.ExtId=0;
		TxMessage.IDE=CAN_ID_STD;//选择发送标准帧
   		//TxMessage.StdId=0;
		//TxMessage.ExtId=0xFFFFFFFF>>3;//扩展帧只有18位,在32位数据时最后三位为(IDE,RTR,TXRQ),所以在写扩展帧时,最后三位要置0
    
		
		//TxMessage.IDE=CAN_ID_EXT;
		//发送扩展帧
		TxMessage.RTR=CAN_RTR_DATA;//发送的是数据帧
	//TxMessage.RTR=CAN_RTR_REMOTE;//远程帧,只发送ID,不发送数据,将ID发给另一台设备,请求另一台设备返回数据
		TxMessage.DLC=8;//数据长度8B
		
		TxMessage.Data[0]=0x11;
		TxMessage.Data[1]=0x22;
		TxMessage.Data[2]=0x33;
		TxMessage.Data[3]=0x44;
		TxMessage.Data[4]=0x55;
		TxMessage.Data[5]=0x66;
		TxMessage.Data[6]=0x77;
		TxMessage.Data[7]=0x88;
		//数据内容
		can_tx_success_flag = 0;
       CAN_Transmit(CAN1,&tx_message);//can发送数据
       while(can_tx_success_flag == 0);//是否一次发送成功
		delay_ms(1000);//1s一次 
	}	
}

void RCC_Configuration(void)
{
    SystemInit();//72m
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
}

void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;	
	
	//端口重映射
	GPIO_PinRemapConfig(GPIO_Remap1_CAN1,ENABLE);

	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;//RX
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_Init(GPIOB,&GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}

void NVIC_Configuration(void)
{
   	NVIC_InitTypeDef NVIC_InitStructure; 

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 

	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
	NVIC_Init(&NVIC_InitStructure);
}

void CAN_Configuration(void)
{
	//硬件上有个can/usb才能与PC通讯
   CAN_InitTypeDef CAN_InitStructure;
   CAN_FilterInitTypeDef CAN_FilterInitStructure;

   CAN_DeInit(CAN1);
   CAN_StructInit(&CAN_InitStructure);

   //关闭时间触发模式
   CAN_InitStructure.CAN_TTCM=DISABLE;
   //关闭自动离线管理
   CAN_InitStructure.CAN_ABOM=DISABLE;
   //关闭自动唤醒模式
   CAN_InitStructure.CAN_AWUM=DISABLE;
   //禁止报文自动重传
   CAN_InitStructure.CAN_NART=DISABLE;
   //FIFO溢出时报文覆盖源文件
   CAN_InitStructure.CAN_RFLM=DISABLE;
   //报文发送优先级取决于ID号,本次只用了一个发送邮箱,关闭TXFP
   CAN_InitStructure.CAN_TXFP=DISABLE;
   //工作模式(正常)
   CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;

   //波特率设置125 KBPS

   CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
   CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;
   CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;
   CAN_InitStructure.CAN_Prescaler = 48;


   //初始化CAN
   CAN_Init(CAN1,&CAN_InitStructure);

   //屏蔽滤波(can接收才涉及)
   CAN_FilterInitStructure.CAN_FilterNumber=0;//0号滤波器
   //屏蔽滤波模式
   CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//标识符屏蔽位模式
   //32位寄存器
   CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
   //标识符寄存器高16位
   CAN_FilterInitStructure.CAN_FilterIdHigh=0x0F00;
   //标识符寄存器低16位
   CAN_FilterInitStructure.CAN_FilterIdLow=0;
   //屏蔽寄存器高16位
   CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0F00;
   //屏蔽寄存器低16位
   CAN_FilterInitStructure.CAN_FilterMaskIdLow=0;
   //过滤器将ID报文关联到FIFO0缓存区中,数据只能从这里导出
   CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;
   //过滤器使能
   CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
   //初始化过滤器
   CAN_FilterInit(&CAN_FilterInitStructure);

   //接收中断使能
   CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
   //发送中断使能
   CAN_ITConfig(CAN1,CAN_IT_TME,ENABLE);
}

void USB_LP_CAN1_RX0_IRQHandler(void)
{
	CanRxMsg RxMessage;
	CanTxMsg TxMessage;

	//CAN接收
	CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);//can接收的数据存在FIFO0的RxMessage里

	TxMessage.StdId=RxMessage.StdId;//标准ID
	TxMessage.ExtId=RxMessage.ExtId;//扩展ID
	TxMessage.IDE=RxMessage.IDE;//标准帧还是扩展帧
	TxMessage.RTR=RxMessage.RTR;//数据帧还是远程帧
	TxMessage.DLC=RxMessage.DLC;//待传输数据长度

	TxMessage.Data[0]=RxMessage.Data[0];
	TxMessage.Data[1]=RxMessage.Data[1];
	TxMessage.Data[2]=RxMessage.Data[2];
	TxMessage.Data[3]=RxMessage.Data[3];
	TxMessage.Data[4]=RxMessage.Data[4];
	TxMessage.Data[5]=RxMessage.Data[5];
	TxMessage.Data[6]=RxMessage.Data[6];
	TxMessage.Data[7]=RxMessage.Data[7];
	//CAN发送
	CAN_Transmit(CAN1,&TxMessage);
}
//进发送中断的目的是为了设置can发送成功标志位
void USB_HP_CAN1_TX_IRQHandler(void) //CAN TX
{
    if (CAN_GetITStatus(CAN1,CAN_IT_TME)!= RESET)
	{
	   CAN_ClearITPendingBit(CAN1,CAN_IT_TME);
       can_tx_success_flag=1;
    }
}

 

  • 14
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Modbus RTU通信协议是一种基于串行通信的通信协议常用于工业自动化领域。STM32是一款由STMicroelectronics推出的系列32位微控制器,具有高性能和丰富的外设功能。 要使用Modbus RTU通信协议STM32上进行通信,可以采取以下步骤: 1. 配置串口:选择一个合适的串口并进行相应的初始化配置,包括波特率、数据位、停止位和奇偶校验位等设置。这些配置应该与Modbus RTU设备(如PLC或传感器)的设置匹配。 2. 实现Modbus RTU协议:在STM32上实现Modbus RTU协议,需要编写相关代码来处理通信协议的帧结构、数据解析和响应等。这包括解析从Modbus主设备接收到的命令帧,执行相应的功能,并将响应数据打包为响应帧发送回Modbus主设备。 3. 与外部设备通信:通过STM32的串口与外部Modbus RTU设备进行通信。可以使用适当的USART或UART外设,使用串口驱动程序传输和接收消息。 4. 调试和测试:实现后,需要进行调试和测试以确保通信的正确性和稳定性。可以使用调试工具或虚拟串口软件模拟Modbus从设备,验证STM32的通信功能。 总结来说,要在STM32上使用Modbus RTU通信协议,需要配置串口、实现Modbus RTU协议、进行外部设备的通信和进行调试和测试。这样可以实现STM32与其他Modbus RTU设备之间的可靠通信。 ### 回答2: Modbus RTU是一种常用的串行通信协议,适用于STM32等微控制器的通信应用。该协议使用简单的二进制编码方式进行数据传输,支持点对点和多点通信。 在STM32上实现Modbus RTU通信协议,首先要了解协议的基本结构和传输规则。Modbus RTU使用了RS-485物理层接口和UART串口通信协议进行数据传输。通过对UART和GPIO的配置,可以轻松实现RS-485的硬件连接,并使用UART进行数据的发送和接收。 在软件层面上,可以使用STM32的库函数或者第三方库来实现Modbus协议的解析和封装。首先需要对接收到的数据进行解析,提取出地址、功能码、寄存器地址和数据等字段。然后根据功能码进行相应的操作,如读取或写入寄存器的数据。 对于Modbus RTU通信协议,需要注意以下几点: 1. 通信速率:根据具体需求选择合适的通信速率,常见的有9600、19200等。 2. 地址设置:每个设备都有独一无二的地址,通信时需要根据地址进行寻址。 3. 异常处理:在通信过程中,可能会发生通信错误或者设备故障,需要合适地处理异常情况。 在使用Modbus RTU通信协议时,可以根据具体应用需求选择合适的通信方式,如点对点通信或者多点通信。可以使用STM32提供的硬件资源和软件编程能力,来实现Modbus RTU通信协议并实现设备之间的数据交换。 ### 回答3: Modbus RTU是一种串行通信协议常用于实现设备之间的通信。STM32是一系列基于ARM Cortex-M内核的微控制器产品。 Modbus RTU协议通过串行通信方式实现设备之间的数据传输。它是一种基于从站/主站的通信方式,通常需要一台主机设备(主站)和多台从机设备(从站)。主站通过发送指令来读取或写入从站设备中的寄存器值。Modbus RTU协议使用二进制编码,可以在串行通信支持的较低速率下进行通信,具有较高的实时性和稳定性。 STM32是一家STMicroelectronics推出的微控制器产品系列,使用ARM Cortex-M内核。它具有低功耗、高计算性能和丰富的外设资源,常用于工业自动化、智能家居、安全控制等领域。STM32系列微控制器支持Modbus RTU协议,通过串口或UART接口与其他设备进行通信。 在STM32控制器中,可以通过配置串口或UART模块来实现Modbus RTU通信。首先,需要在STM32的引脚配置和时钟设置中进行相应的初始化。然后,通过编程设置串口或UART的参数,如波特率、数据位数、停止位数等。接下来,可以使用STM32的通信接口库函数来发送和接收Modbus RTU协议的数据帧。 总而言之,Modbus RTU是一种常用的串行通信协议,需要通过合适的硬件设备和适当的编程来实现。在STM32控制器中,可以通过串口或UART模块来支持Modbus RTU通信。这种通信方式在工业自动化和其他领域中具有广泛的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值