随笔 - 63  文章 - 1  评论 - 19  阅读 - 33239

【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那端接收的数据。

程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#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   凡仕  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示