【WCH蓝牙系列芯片】-基于CH32V208开发板—RS-485串口收发数据通信
------------------------------------------------------------------------------------------------------------------------------------
整个RS-485的通信原理,可以参考https://www.cnblogs.com/ZYL-FS/p/18592401
先看一下硬件原理图,485电平转换芯片硬件连接,CH32V208使用串口1的PA9(TX)和PA10(RX)还有一个收发模式的控制脚PA1。将CH32V208的RXD(PA1)直接连接485芯片的RO引脚;通过TXD(PA9)直接连接485芯片的DI引脚,该485芯片处于发送模式还是接收模式的选择位是DE/!RE,一般情况下把这两个引脚接在一起,只用CH32V208的一个引脚PA1直接连接TNOW0.
当CH32V208的PA1输出的信号TNOW0为高电平,则芯片处于发送模式
当CH32V208的PA1输出的信号TNOW0为低电平,则芯片处于

在程序串口初始中,配置PA1为复用推挽输出,还有串口脚PA9,PA10,分别配置为复用推挽输出和浮空输入模式。并直接设置PA1引脚是低电平,让485芯片默认是接收模式。


RS485_Send_Data是485发送数据函数,将PA1设置为高电平,为发送模式

RS485_Receive_Data是485查询接收到的数据,将PA1设置为低电平,为接收模式

在主程序中,先485那端先接收串口发送的数据,然后将接收到数据rx485buf再全都复制一遍到tx485buf中,再利用RS485_Send_Data函数,将发送的数据,再回传到串口,并显示。可以通过下端的串口调试工具来观察。串口打印那段也可以看到485那端接收的数据。


程序如下:
#include "debug.h"
#define buffer_len 256
u8 USART_Rbuffer_Num = 0;
u8 USART_Tbuffer_Num = 0;
u8 USART_Rbuffer[buffer_len];//接收缓冲区数组
void USART1_Init(uint32_t bound)
{
GPIO_InitTypeDef GPIO_InitStructure={0};
USART_InitTypeDef USART_InitStructure={0};
NVIC_InitTypeDef NVIC_InitStructure={0};
/* 打开GPIO和USART部件的时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//485_RE_DE控制引脚
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1; //模式选择PA1(CS)
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // IO口频率
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; // 复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); // 初始化
/* 配置GPIO的模式和IO口 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; // 串口输出PA9(TX)
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // IO口频率
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); // 初始化
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; // 串口输入PA10(RX)
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;// 浮空输入
GPIO_Init(GPIOA,&GPIO_InitStructure); // 初始化
/* 配置串口硬件参数 */
USART_DeInit(USART1);
USART_InitStructure.USART_BaudRate = bound; /* 波特率 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_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);
/* 使能串口1中断 */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_ClearFlag(USART1, USART_FLAG_RXNE);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* 使能串口空闲中断 */
USART_Cmd(USART1, ENABLE); /* 使能串口 */
//默认接收
GPIO_ResetBits(GPIOA, GPIO_Pin_1); //设置RE、DE引脚低电平,接收状态
}
// 用于发送单个字节的数据
void USARTx_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
USART_SendData(pUSARTx, data);
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
//用于发送一个字符串
void USARTx_SendStr(USART_TypeDef* pUSARTx, char *str)
{
uint8_t i = 0;
do
{
USARTx_SendByte(pUSARTx, *(str+i));
i++;
}while(*(str+i) != '\0');
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}
//RS485发送len个字节.
//buf:发送区首地址
//len:发送的字节数(为了和本代码的接收匹配,这里建议不要超过64个字节)
void RS485_Send_Data(u8 *buf,u8 len)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1); //设置为发送模式
u8 t;
for(t=0;t<len;t++) //循环发送数据 Q
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); // 等待USART1的发送完成标志(TC)被设置
USART_SendData(USART1,buf[t]); // 将buf数组中的第t个字节发送出去
}
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); // 发送完所有数据后,这个循环再次等待USART1的发送完成标志被设置
USART_Tbuffer_Num=0; // 清空发送缓冲区
}
//RS485查询接收到的数据
//buf:接收缓存首地址
//len:读到的数据长度
void RS485_Receive_Data(u8 *buf,u8 *len)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1); //设置为接收模式
u8 rxlen=USART_Rbuffer_Num; // USART接收缓冲区中的数据数量
u8 i=0;
*len=0; //默认为0
Delay_Ms(10); //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
if(rxlen==USART_Rbuffer_Num&&rxlen) //接收到了数据,且接收完成了
{
for(i=0;i<rxlen;i++)
{
buf[i]=USART_Rbuffer[i]; // USART接收缓冲区中的数据复制到用户提供的缓冲区buf中
}
*len=USART_Rbuffer_Num; //记录本次数据长度
USART_Rbuffer_Num=0; //清零
}
}
/*********************************************************************
* @fn main
*
* @brief Main program.
*
* @return none
*/
int main(void)
{
u8 value; // 存储接收到的数据长度
u8 i=0;
u8 tx485buf[9]={9,8,7,6,5,4,3,2,1}; // 存储要发送的数据
u8 rx485buf[9]={0}; // 用于存储接收到的数据
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置中断的优先级
SystemCoreClockUpdate(); // 更新系统核心时钟
Delay_Init();
USART_Printf_Init(115200); // 串口打印初始化
printf("USART Interrupt TEST\r\n");
USART1_Init(115200); // 串口1初始化
while(1)
{
//接收
RS485_Receive_Data(rx485buf,&value); // 调用RS485_Receive_Data函数接收数据,存储到rx485buf数组中,并将接收到的数据长度存储在value变量中
printf("value1=%d\r\n",value); // 打印接收到的数据长度
if(value)//接收到有数据
{
for(i=0;i<value;i++)
{
tx485buf[i]=rx485buf[i]; // 将rx485buf中的数据复制到tx485buf中
printf("receive=%x\r\n",(u8)rx485buf[i]); // 打印每个接收到的数据字节
}
}
Delay_Ms(1000);
RS485_Send_Data(tx485buf,value); // 发送tx485buf数组中的数据,长度为9个字节
}
}
void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //中断产生
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志
USART_Rbuffer[USART_Rbuffer_Num] = USART_ReceiveData(USART1); //接收数据
USART_Rbuffer_Num++;
}
}
浙公网安备 33010602011771号