【WCH蓝牙系列芯片】-基于CH32V208开发板—RS-485串口收发数据通信

------------------------------------------------------------------------------------------------------------------------------------

  现在利用CH32V208芯片,实现RS-485串口收发数据程序的实现。

  整个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++;
    }
}

  

 

posted on 2024-12-26 09:35  凡仕  阅读(18)  评论(0编辑  收藏  举报