本文用的单片机是原子的战舰V4
1. 先来驱动一下usart2
USART
驱动配置一般步骤:
STEP1:使能相关时钟,这块板子usart2用到了
A2
、A3
分别为TX
脚、RX
脚,D7
的作用是发送接收模式控制。下面开启GPIO与USART2时钟:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE);
STEP2:初始化GPIO,A2A3D7三个IO口都要去初始化,其中TX功能IO要设置为复用推挽输出,RX功能IO要设置为浮空,D7作为发送接收控制要设为推挽输入。
/*GPIO初始化--Ck*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;//CK
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStruct);
/*GPIO初始化--TX*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;//TX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/*GPIO初始化--RX*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3; //RX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStruct);
STEP3:接下来是
USART
与NVIC
的初始化,串口初始化主要设置波特率、控制流、校验、停止位等,初始化完之后记得开启一下串口中断;NVIC
初始化则需要设置中断通道使能、优先级等。我们默认设置为接收模式
USART_InitStruct.USART_BaudRate = bound;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_Init(USART2, &USART_InitStruct);
/*开启串口中断*/
USART_ITConfig(USART2, USART_IT_RXNE,ENABLE); //接收中断,当接收到1个字节,会产生USART_IT_RXNE中断
/*使能串口*/
USART_Cmd(USART2,ENABLE);
/*NVIC初始化*/
NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn; //USART2通道使能
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //子优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
STEP4:接着去写中断服务函数即可,这里先写一个简单的,下载程序后可实现“串口助手发什么就能接收到什么”。
void USART2_IRQHandler(void){
u8 res;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收到数据
{
res =USART_ReceiveData(USART2);
USART_SendData(USART2,res);
}
}
最后不要忘记在主程序中配置中断优先级分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
这样我们一个简单的串口通信就完成了。
2. Motbus485通信在USART基础上又应该怎么实现
首先这边是我们的h文件,只是一些定义和声明,不详细介绍。
#ifndef __USART2_H
#define __USART2_H
#include "sys.h"
#define RS485_REC_LEN 64 //定义最大接收字节数 200
//模式控制
#define RS485_TX_EN PDout(7) //485模式控制.0,接收;1,发送.
#define EN_USART2_RX 1 //使能(1)/禁止(0)串口1接收
extern u8 RS485_RX_BUF[RS485_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_CNT; //接收状态标记
void usart2_init(u32 bound);
void RS485_Receive_Data(u8 *buf,u8 *len);
void RS485_Send_Data(u8 *buf,u8 len);
#endif
中断服务函数修改:我们将接收到的数据放到一个数组中存起来。这里我们做了一个条件编译
#ifdef EN_USART2_RX...#endif
。可以看到相对于前面写的中断服务函数并没有什么改变,我们并没有直接将接收到的数据发出来,而实现存到一个数组里面。
#ifdef EN_USART2_RX //如果使能了接收
u8 RS485_RX_BUF[RS485_REC_LEN]; //定义接收缓冲200字节
u16 USART_RX_CNT=0; //接收状态标记
void USART2_IRQHandler(void){
u8 res;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收到数据
{
res =USART_ReceiveData(USART2); //读取接收到的数据
if(USART_RX_CNT<64)
{
RS485_RX_BUF[USART_RX_CNT]=res; //记录接收到的值
USART_RX_CNT++; //接收数据增加1
}
}
}
#endif
接着写一下485接收程序,这边要做的事情其实就是将
usart
接收到的数据存到buf中。相当于是将数据从RS485_RX_BUF
转到buf
中,之后要做数据处理,我们直接对这个buf
做数据处理即可。
void RS485_Receive_Data(u8 *buf,u8 *len){
u8 rxlen = USART_RX_CNT;
u8 i = 0;
*len = 0;
delay_ms(10);//等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
if(rxlen == USART_RX_CNT&&rxlen){//接收到了数据,且接收完成了
for(i = 0; i < rxlen; i++){
buf[i] = RS485_RX_BUF[i];
}
*len = USART_RX_CNT;
USART_RX_CNT = 0; //清0
}
}
写一下485发送数据的程序,我们要判断数据是否发完了,没有发完就用
USART_SendData
去发
先了解一下USART_FLAG_TC
这个标志是干嘛的
当发送移位寄存器中的1字节数据已经通过TX脚一位一位的移出去后,该标志位就会被置1,从而引发该事件的中断。所以,其实USART_FLAG_TC就是用来标志 “发送移位寄存器中的数据有没有全部发送出去” 这件事的。
void RS485_Send_Data(u8 *buf,u8 len){
u8 t;
RS485_TX_EN=1; //设置为发送模式
for(t=0;t<len;t++) //循环发送数据
{
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
USART_SendData(USART2,buf[t]);
}
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
USART_RX_CNT=0;
RS485_TX_EN=0; //设置为接收模式
}
我们定义了一个要发送的数据数组与数据接收数组,接着发送、接收。
u8 TR_Read[8]={0x01,0x03,0x00,0x00,0x00,0x02,0xC4,0x0B};
u8 rs485buf[20]={0};
RS485_Send_Data(TR_Read,8);
delay_ms(300);
RS485_Receive_Data(rs485buf,&len);
实验现象:接着打开串口进行测试,指令就发出来了。
一般情况下,我们只要向485传感器发送相关指令,就可以驱动这种传感器了。比如你要获取传感器数据,你就发送数据获取指令;需要修改地址,就发送修改地址的指令。485收发你都会了,传感器驱动哪里还是什么问题呢。
创作不易!希望收获你的点赞与关注👍🤝🤝