关注分享主机优惠活动
国内外VPS云服务器

基于UCOSII(STM32F107)的RS485通信

总结:为了可靠运行,在发送或接收数据之前总线改变状态时必须有适当的延迟。

1、实现效果

基于ucosii实时操作系统的RS485通信采用USART+DMA进行收发。

2.开发环境 开发工具:KEIL V5 开发板:STM32f107RC 使用方式:USART + DMA 使用系统:UCOSII III、RS485 部分原理

RS-485 通信网络在节点上使用串行端口控制器。 RX和TX信号线连接到收发器,收发器通过差分线连接到网络总线。 通常,TTL 信号用于串行端口控制器和收发器之间,差分信号用于收发器和总线之间。

发送数据时,串口控制器的TX信号被收发器转换为差分信号,它将被传递到公共汽车上。

收发器在接收数据时,将总线上的差分信号转换为TTL信号并通过Send via。 RX 引脚连接到串行端口控制器。

MCU 引脚输出 TTL 电平。 TTL电平表示MCU引脚输出0电平。 通常,正常情况下电压为0V。 当MCU端子输出1电平时,电压为5V。 由于TTL电平是在信号线和地线上产生的,因此信号线上的干扰信号会跟随有效信号传播到接收端,从而产生有效信号。信号受到干扰,485通信实际上是通过硬件层的转换芯片将来自MCU的TTL电平进行转换

RS-485通信网络最大传输距离可达1200米,总线上可承载128个通信节点。 由于RS-485网络只有一对差分信号线,因此采用差分信号来表示逻辑。 如果两条线AB之间的电压差为-6V至-2V,则代表逻辑1。 +2V 和 +6V 之间的电压差代表逻辑 0。 一次只能表示一个值。 时间。 由于它是信号,因此通信是半双工的。

在单个实验板上,STM32 作为串行端口控制器从 USART 外设引出 TX 和 RX 引脚,并将它们连接到 RS-485 收发器 MAX485,后者使用其 A 和 B 引脚。连接到 RS-485 总线网络。 为了方便起见,每个实验板上的A和B之间连接了一个120Ω电阻作为RS-485总线的终端电阻。 将实验板作为常规节点连接时要小心。 。 如果使用现有的 RS-485 总线,请勿添加此电阻。

MAX485芯片有两个引脚“RE”和“DE”,这些是485芯片。 发送/接收操作状态,当RE引脚为低电平时,485芯片处于接收状态,当DE引脚为高电平时,芯片处于发送状态。 实验板上使用的STM32 PD11直接连接这两个引脚,通过控制PD11的输出电平可以控制485的发送和接收状态。

只需在实验板之间连接 A 到 A 和 B 到 B 即可。

4、设置操作

创建了 5 个任务

任务名称Task_Com4_PRIO 4 COM4 通讯任务 当然也包括系统任务。 OS_TaskIdle 空闲任务 [k4 ]--------[ k4]-[ k4]---[k4 ]- 具有最低优先级 OS_TaskStat 计算执行时间的任务 ------ - 第二低优先级

4.1 主任务创建

//创建最高优先级的主任务。 建立这个任务的另一个目的是为了以后统计任务的使用。 os_err = OSTaskCreate((void ( *) (void *)) App_TaskStart, (void *) 0, //任务代码指针 (void *) 0, //任务开始执行时传递给任务的参数指针 (OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1], //分配给任务的栈顶指针从上到下递减(INT8U APP_TASK_START_PRIO)。 //分配给任务的优先级 static void App_TaskStart(void* p_arg) { (void) p_arg //为ucos启用统计任务# if (OS_TASK_STAT_EN > 0) //--- - 统计任务初始化函数 OSStatInit(); /* 确定 CPU 容量。 */ #endif //创建另一个任务 App_TaskCreate(); while ( 1) { // 每秒循环一次 OSTimeDlyHMSM(0, 0,1, 0); } } 4.2 创建另一个任务 static void App_TaskCreate( void) { //CPU_INT08U os_err; //Com1_SEM=OSSemCreate(1); //为串口4中断创建信号量 Com4_MBOX = OSMboxCreate((void *) 0); //为串口4中断创建消息邮箱 //发送和接收串口4 Task -[ k4]---------------- -[ k4]------- ]-----[k4 ]-[ k4]---------------- -[k4 ]---- OSTaskCreateExt(Task_Com4, //指向任务任务代码的指针 (void *)0, //任务开始执行时在任务中创建指向任务代码的指针Passed argument (OS_STK *)&Task_Com4Stk[ Task_Com4_STK_SIZE-1], //分配给任务的栈顶指针从上到下 Task_Com4_PRIO, //分配给任务的优先级 Task_Com4_PRIO, //为将来保留的特殊标识符versions,与当前版本相同 任务优先级 (OS_STK *)&Task_Com4Stk[0], //任务栈底指针,用于栈验证 Task_Com4_STK_SIZE, //指定用于堆栈验证的堆栈容量 (void *)0, //指向用户附加数据字段的指针,用于扩展任务的任务控制块 OS_TASK_OPT_STK_CHK |OS_TASK_OPT_STK_CLR); //选项,例如是否允许堆栈检查、是否将堆栈清0、任务是否应该执行浮点运算等。 } 4.2.1 建立子任务-串口通信任务

串口通信任务:这里消息邮箱用于发送消息。

在其他任务App_TaskCreate(void)建立之初,首先建立串口通信消息邮箱。 Com4_MBOX=OSMboxCreate((void *) 0); 接下来进入串口通信任务循环后,等待消息邮箱信息(第8行)。 如果您没有收到消息,请等待。 在此期间您可以执行其他任务。 当发送消息时,串行通信具有高优先级,因此可以快速响应并根据收到的消息进行定制。 由于串口接收需要中断,因此我们对串口通信的接收中断部分进行说明。 static void Task_Com4(void *p_arg){ INT8U error; unsigned char * msg; (void)p_arg; while(1){ //OSSemPend(Com1_SEM,0,&err); //串口接收成功for the signal Quantity msg=(unsigned char *)OSMboxPend(Com4_MBOX, 0,&err); //串口成功接收命令后等待邮箱信息 //输出邮箱信息的前10个数据if(msg != NULL) {for(i = 0; i < 2; i++){G_u8Usart1SendBuf[i] = 0x10;}USART_DMA_SendStart(DMA2_Channel5, 2);memcpy(G_u8Usart1SendBuf, msg, 10);USART_DMA_SendStart(DMA2_Channel5, 1 ) 0 );} //DealWith_Data(pfifo); //处理数据} }

下面是接收串口数据的串口中断函数。 一旦发现是一个完整的帧,就会调用 OSMboxPost(Com4_MBOX,(void *)&msg); 当你发送电子邮件时,那里的串口任务会执行从挂起到唤醒的相应过程。

使用环形缓冲区可以实现任意数据类型的 FIFO 处理并接收数据。 参见:stm32f0串口DMA空闲中断接收-基于HAL库(代码)_Puffbug博客-CSDN博客

void UART4_IRQHandler(void){ uint16_t t;unsigned int i;unsigned char msg[ 50] ;OS_CPU_SR cpu_sr ;OS_ENTER_CRITICAL() //保存全局中断标志并关闭全局中断/OSIntNesting++;OS_EXIT_CRITICAL(); //恢复全局中断标志 if(USART_GetITStatus(UART4,USART_IT_IDLE) == SET ) //检查是否有中断发生 {RS485_TX_EN = 0; DMA_Cmd(DMA2_Channel3,DISABLE); //关闭DMA传输 DMA_ClearFlag( DMA2_FLAG_TC3 ); t = DMA_GetCurrDataCounter(DMA2_Channel3); //获取剩余容量 //FIFO_Add(pfifo, G_u8Usart1RecvBuf, UART4_RECV_MAXLEN - t); //保存 FIFO 数据 memcpy(msg, G_u8Usart1RecvBuf, UART4_RECV_MAXLEN - t) OSMboxPost (; Com4_MBOX,(void *)&msg);DMA_SetCurrDataCounter(DMA2_Channel3,UART4_RECV_MAXLEN); //重置发送次数 DMA_Cmd(DMA2_Channel3,ENABLE); //启用DMA发送 USART_ReceiveData(UART4); //读取一次数据 . 如果没有,请继续。 Interrupt USART_ClearFlag(UART4,USART_FLAG_IDLE); //清除串口中断标志}OSIntExit();} 4.3 硬件初始化部分 void BSP_Init(void){ /* NVIC 设置 */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); RS485_init (9600); ; 惰性初始化(); //惰性函数初始化 } 4.4 RS485传输函数

注意:485芯片通讯时要特别注意对 4 的。85 控制终端DE的软件编程。 为了可靠运行,在发送或接收数据之前切换 485 总线状态时需要适当的延迟。 具体方法如下。

在数据传输状态下,先将控制端设置为“1”,进行延迟。 大约1ms发送有效数据,数据包发送后延迟1ms控制端置“0”。 这个过程确保总线在改变状态时可靠地运行。 代码延迟10ms(参考:https://blog.csdn.net/yx_l128125/article/details/7914102)

#define RS485_TX_EN PAout(15) 设置RS485模式控制。 RX:0,TX:1Void USART_DMA_SENDSENDSTART(DMA_CHANNEL_TYPEDEF *DMA_STREAMX,U16 M_U16SENDCNT){USART_DMACMD(UART4,USART_DMAREQ_TX,usart_dmareq_tx,enable) 0)延迟 DMA_Setcurredatacounter (DMA_StreamX, m_u16sendCnt); DMA_CMD (DMA_StreamX, Enable)! = Reset) // µè'ýíě5 êäí êää³é {DMA_CLEARFLAG (DMA2_FLAG_TC5);//"Break" }}delay_ms(10);//延迟RS485_TX_EN=0; 4.5 主函数 int main(void){ unsigned char os_err;OSInit(); //硬件初始化 BSP_Init(); //FIFO环处理 初始化数据 pfifo = &fifo;FIFO_Init(pfifo, aRxFIFOBuffer, sizeof(uint8_t), RXFIFOBUFFERSIZE); //先发送一些数据。 这是可阻止的 for(i = 0; i < 50; i++){G_u8Usart1SendBuf[i] = 0x10 + i;}USART_DMA_SendStart(DMA2_Channel5, 50); os_err = OSTaskCreate((void (*) (void *)) App_TaskStart , ( void *) 0, //指向任务代码的指针 (void *) 0, //任务启动 指向执行过程中传递给任务的参数的指针 (OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1], //指向任务分配的堆栈起始指针从上到下递减 (INT8U) APP_TASK_START_PRIO); //分配给任务的 OSTimeSet(0) 优先级; /* 启动多任务*/} 5. 执行字符串调试端口

参考:[stm32][ucos] 1.基于ucos操作系统的LED闪烁和串口通信的简单例程- beautifulzzzz[ k4]博客园

stm32f0串口DMA空闲中断接收——基于HAL库(代码)_Puff Bug博客-CSDN博客

代码:

https://download.csdn.net/download/qq_41070511/24419255

未经允许不得转载:主机频道 » 基于UCOSII(STM32F107)的RS485通信

评论 抢沙发

评论前必须登录!