[三菱] 基于RS232 接口的 Modbus-RTU 从机实现(RA6M4)

[复制链接]
查看73462 | 回复0 | 2024-4-14 23:45:40 | 显示全部楼层 |阅读模式
踏浪而行,偶尔回首,虽不见印记,却也能望见远处的海岸。

从15年毕业,恍然已八年。

硬件工作了八年。也是爱的深沉。

还记得大学的时候在学生会认识的朋友,他有一天突然跟我推荐单片机开发板,那时候大二,打听过,单片机应该是下学期开始的课程。当时我觉得是一种命运的安排,就斥巨资购买了郭天祥的单片机开发板。鬼使神差的,竟然在大学那松散的时光里,我可以学习到深夜一两点!也是因为一块开发板,我考了两次的计算机二级(虽然后来知道没啥用),就很自然的过了。以前不是很理解的硬件知识,也通畅了。后来参加了学校组织的以及国家级的多次比赛,硬件开始让我爱不释手。在当时我也成为了我们班的专业代表,然而毕业始终给人猝不及防。

后来,经过一番忙碌,进入了现在的企业。

还记得简历上不敢写面试硬件工程师,最终写了个PCB工程师。或许也比较怀疑自己的硬件设计能力吧。

刚入职,大多是熟悉产品,于是我维修了公司的陈年旧板,看原理图,查资料,大部分还是需要自主去弄的。然后PCB的设计,学习cadence软件,设计第一块接口板。

恍惚一年多,五六层板也很轻松了。记得有一次评估PCB尺寸和接口位置,对应产品外观。逼不得已学习了最简单的SolidWorks操作。也算是初涉结构设计,后来我们结构设计工程师离职,我就揽下了这个工作。自古硬件结构不分家。PCB与结构的搭配产生了完美的产品。

就这样一晃就是四年,作为干硬件的竟然连原理图都没弄过,挺遗憾的,正当要得过且过的时候,也不知为啥我的领导开始疯狂输出各种原理图设计给我,并且算得上的手把手教学了,但是时间只给了我一个月,因为他要离职了,并且让我接替。有种悲喜交加的感觉。喜的是升职加薪,悲的是刚好两个项目来了。原理图、PCB、结构...

就从原理图认真开始吧,反正也只能这样。于是参考着参考设计,本想着删删减减就大功告成的,然而就在删电容的时候就卡住了,脑海中全是疑问:这个电容为什么选这个容量的?为什么耐压值是这个?这里没标注电容的材料啊?哎?为啥这个地方要这么多种类的电容啊?算了还是删电阻吧,然后又是疑问:多大电阻?多少精度?多大封装?后来还有电感...

最终的结果是全部保留原样的,反正能用,就不改了。最终导致了bom成本,板卡做的很大等问题。

第一次可以这样做,第二次也可以,但是等产品出来了,市面上同类产品,我们的定价颇高,于是老板请我去他办公室喝茶了。意思很简单,降bom成本。

路漫漫修远以下是面包板社区“瑞萨RA6M4 MCU 评估板”评测活动的评测连载,分享于此,希望对你有所参考。
(1)开发环境搭建
(2)快速傅里叶变换(FFT)测试
(3)定时器实现SPWM
(4)基于RS232 接口的 Modbus-RTU 从机实现

1、modbus 协议是工业运用比较成熟的通信协议,本例基于瑞萨RA6M4单片机进行modbus协议的实现,开源的modbus 协议较多,本例以移植Xtiny-Modbus为展示:

(1)第一步:搭建硬件环境

由于开发板没有带串口,需要外接一个串口收发模块



(2)第二步:下载开源的源码,下载地址:Xtiny-Modbus移植示例 https://gitee.com/zhang_en/xtiny_-modbus_test.git

(3)第三步:建立工程,配置时钟

由于外部高速晶振24MHz没有焊接,需要配置为内部晶振16MHz,然后再2分频



(4)第四步:配置串口

设置波特率、回调函数、中断优先级



(5)第五步:配置定时器

设置定时器计时的周期,回调函数、中断优先级



(6)第六步:编写串口驱动函数

#include"usart3.h"#include"Sys_Config.h"#if MD_USD_SALVE#include"MDS_RTU_Serial.h"#else#include"MDM_RTU_Serial.h"#include"MD_RTU_SysInterface.h"#include"MDM_RTU_Fun.h"#endif

volatileuint8_t flag=false;

voidRS485RWConvInit(void){//收发引脚配置//        R_IOPORT_Open(&g_ioport_ctrl,g_ioport.p_cfg);//        R_IOPORT_PinWrite(&g_ioport_ctrl,BSP_IO_PORT_05_PIN_03,BSP_IO_LEVEL_LOW);    }
//串口1配置voidinit_usart3(void){            R_SCI_UART_Open(&g_uart0_ctrl,g_uart0.p_cfg);            RS485RWConvInit();    }voidusart3_send_byte(uint8_t byte){            R_SCI_UART_Write(&g_uart0_ctrl,(uint8_t*)(&(byte)),1);while(flag!=true);            flag=false;    }voidusart3_send_bytes(uint8_t *bytes,int len){int i;for(i=0;i<len;i++){                    usart3_send_byte(bytes);            }    }voidusart3_send_string(char *string){while(*string)            {                    usart3_send_byte(*string++);            }    }
voiduart_callback(uart_callback_args_t *arg){uint8_t data_r;switch(arg->event)            {case UART_EVENT_RX_CHAR://                        R_SCI_UART_Read(&g_uart0_ctrl,(u8*)(&(data_r)),1);                            data_r=(uint8_t)(arg->data);#if !MD_RTU_USED_OS#if MD_USD_SALVE                                            MDSSerialRecvByte(data_r);#else#if MDM_USD_USART3                                                    MDMSerialRecvByte(data);#endif#endif#elseextern Modbus_RTU modbus_RTU;                                    MD_RTU_MsgPut((PModbusBase)(&modbus_RTU), MD_RTU_MSG_HANDLE_ARG(&modbus_RTU),(void*)(data),0);#endifbreak;case UART_EVENT_TX_COMPLETE:                            flag=true;break;default:break;            }

    }
(7)第7步编写定时器驱动程序:

#include"tim3.h"#include"Sys_Config.h"#if MD_USD_SALVE#include"MDS_RTU_Serial.h"//#include "MDS_RTU_Serial_1.h"#else#include"MDM_RTU_Serial.h"#endif
volatileuint32_t sys_tick_100us=0;

voidTIM3_Int_Init(void){        R_AGT_Open(&g_timer0_ctrl,g_timer0.p_cfg);        R_AGT_Start(&g_timer0_ctrl);}

voidtimer_callback(timer_callback_args_t *arg){if(arg->event==TIMER_EVENT_CYCLE_END)//        if (timer_interrupt_flag_get(TIMER5, TIMER_INT_FLAG_UP) != RESET)                 {                                  sys_tick_100us++;#if !MD_RTU_USED_OS#if MD_USD_SALVE                        MDSTimeHandler100US(sys_tick_100us);#else                        MDMTimeHandler100US(sys_tick_100us);#endif#endif        }}
(8)第八步:编写应用程序

staticvoidMDS_RTU_UserUpdate(void){            uint16 temp=0xff;            uint16 temp1[]={1,2,3,4,5};            MDS_RTU_WriteCoils(&modbusS_RTU,1,5,&temp);            MDS_RTU_WriteHoldReg(&modbusS_RTU,11, temp);            MDS_RTU_WriteHoldRegs(&modbusS_RTU,5,5,temp1);    }
(9)第九步:编写处理程序

#include"hal_data.h"
#include"tim3.h"#include"Sys_Config.h"#if MD_USD_SALVE#include"MDS_RTU_APP.h"#else#include"MDM_RTU_APP.h"#include"MDM_RTU_Fun.h"#include"MDM_RTU_User_Fun.h"#endif
FSP_CPP_HEADERvoidR_BSP_WarmStart(bsp_warm_start_event_t event);    FSP_CPP_FOOTER
/*******************************************************************************************************************//**    * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function    * is called by main() when no RTOS is used.    **********************************************************************************************************************/voidhal_entry(void){/* TODO: add your own code here */#if MD_RTU_USED_OS            OSInit();         #endif//delay_init();
#if MD_USD_SALVE                    MDS_RTU_APPInit();#else                    MDM_RTU_APPInit();#endif            TIM3_Int_Init();#if MD_RTU_USED_OS            task1=OSCreateTask(mdTestTask0,NULL,6,256);            task2=OSCreateTask(mdTestTask1,NULL,6,256);            SysTick_Config(SystemCoreClock / OS_T IC KS_PER_SEC);            OSStart();#endifwhile(1){#if !MD_RTU_USED_OS#if MD_USD_SALVE                            MDS_RTU_Loop();#else                            MDM_RTU_Loop();                            MDM_RW_CtrlLoop();#endif#endif            }#if BSP_TZ_SECURE_BUILD/* Enter non-secure code */        R_BSP_NonSecureEnter();#endif    }
(10)第十步:连接Modbus 主机,查看结果



END







点击阅读原文,免费申请

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册哦

x
您需要登录后才可以回帖 登录 | 注册哦

本版积分规则