【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++; } }