当前位置: 首页 > news >正文

专门做讲座的英语网站手把手教你用动易做网站

专门做讲座的英语网站,手把手教你用动易做网站,桂林市中心在哪个区,八戒网设计官网STM32-Modbus主机实现-正点原子精英板 实现方案最终实现效果完整工程下载 移植过程 实现方案 使用网上大神的开源Modbus主机框架#xff1a; 链接: 点击跳转. 链接: 源码地址. 融合参考了另一位大神在openedv论坛开源的Modbus主机代码#xff1a; 链接: 点击跳转. 得到本次的… STM32-Modbus主机实现-正点原子精英板 实现方案最终实现效果完整工程下载 移植过程 实现方案 使用网上大神的开源Modbus主机框架 链接: 点击跳转. 链接: 源码地址. 融合参考了另一位大神在openedv论坛开源的Modbus主机代码 链接: 点击跳转. 得到本次的Modbus主机代码。 移植到正点原子STM32F1精英板可结合我发表的 链接: 正点原子精英板移植freemodbus-v1.6. 可实现Modbus主从机当然得使用两个485串口。 最终实现效果 正常通讯 通讯出错重复发送命令 完整工程下载 链接: 点击下载. 移植过程 首先下载解压Modbus主机框架 解压后得到以上文件在mb_port.c 内添加各个函数的具体实现 /*** brief MODBUS串口初始化接口* param baud:串口波特率* param parity:奇偶校验位设置 * return NONE* note 需要根据使用MCU进行移植*/ void mb_port_uartInit(uint32_t baud,uint8_t parity); /*** brief 串口TX\RX使能接口* param txen:0-关闭tx中断 1-打开tx中断* param rxen:0-关闭rx中断 1-打开rx中断 * return NONE* note 需要根据使用MCU进行移植*/ void mb_port_uartEnable(uint8_t txen,uint8_t rxen); /*** brief 串口发送一个byte* param ch:要发送的byte * return NONE* note 需要根据使用MCU进行移植*/ void mb_port_putchar(uint8_t ch); /*** brief 串口读取一个byte* param ch:存放读取一个byte的指针 * return NONE* note 需要根据使用MCU进行移植*/ void mb_port_getchar(uint8_t *ch); /*** brief 定时器初始化接口* param baud:串口波特率,根据波特率生成3.5T的定时* return NONE* note 需要根据使用MCU进行移植*/ void mb_port_timerInit(uint32_t baud); /*** brief 定时器使能* return NONE* note 定时器要清0重新计数*/ void mb_port_timerEnable(void); /*** brief 定时器关闭* return NONE* note 定时器要清0重新计数*/ void mb_port_timerDisable(void);/*** brief 定时器计数清0* return NONE* note 定时器计数清0重新计数*/ void mb_port_timerReset(void);代码较为简单不做过多介绍这里我添加了一个mb_port_timerReset 计数清零函数在mb_host.c 内用到贴一下mb_port.c总的代码 为了方便移植修改使用了一些宏定义。 #include mb_include.h //主机485发送/接收控制端定义 #define MD_MASTER_TX_EN_CLK_FUN RCC_APB2PeriphClockCmd #define MD_MASTER_TX_EN_CLK RCC_APB2Periph_GPIOD #define MD_MASTER_TX_EN_PORT GPIOD #define MD_MASTER_TX_EN_PIN GPIO_Pin_7//主机485串口定义 #define MD_MASTER_USART USART2 #define MD_MASTER_USART_CLK_FUN RCC_APB1PeriphClockCmd #define MD_MASTER_USART_CLK RCC_APB1Periph_USART2 #define MD_MASTER_USART_IRQn USART2_IRQn #define MD_MASTER_USART_IRQHandler USART2_IRQHandler //主机485串口TX RX引脚定义 #define MD_MASTER_TRX_GPIO_CLK RCC_APB2Periph_GPIOA #define MD_MASTER_TRX_GPIO_CLK_FUN RCC_APB2PeriphClockCmd #define MD_MASTER_TRX_GPIO_PORT GPIOA #define MD_MASTER_RX_PIN GPIO_Pin_3 //#define MD_MASTER_RX_SOURCE GPIO_PinSource7 #define MD_MASTER_TX_PIN GPIO_Pin_2 //#define MD_MASTER_TX_SOURCE GPIO_PinSource6 //主机使用的定时器定义 #define MD_MASTER_TIM TIM4 #define MD_MASTER_TIM_CLK RCC_APB1Periph_TIM4 #define MD_MASTER_TIM_CLK_FUN RCC_APB1PeriphClockCmd #define MD_MASTER_TIM_IRQn TIM4_IRQn #define MD_MASTER_TIM_IRQHandler TIM4_IRQHandler#define RS485_Frame_Distance 10 //数据帧最小间隔ms),超过此时间则认为是下一帧void mb_port_uartInit(uint32_t baud,uint8_t parity) {/*串口部分初始化*/GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;//使能USARTGPIOAMD_MASTER_TRX_GPIO_CLK_FUN(MD_MASTER_TRX_GPIO_CLK , ENABLE);MD_MASTER_USART_CLK_FUN(MD_MASTER_USART_CLK , ENABLE);//GPIOA9 USART1_TxGPIO_InitStructure.GPIO_Pin MD_MASTER_TX_PIN;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; //推挽输出GPIO_Init(MD_MASTER_TRX_GPIO_PORT, GPIO_InitStructure);//GPIOA.10 USART1_RxGPIO_InitStructure.GPIO_Pin MD_MASTER_RX_PIN;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; //浮动输入GPIO_Init(MD_MASTER_TRX_GPIO_PORT, GPIO_InitStructure);USART_InitStructure.USART_BaudRate baud; //只修改波特率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(MD_MASTER_USART, USART_InitStructure);//使能USARTUSART_Cmd(MD_MASTER_USART, ENABLE);//设定USART1 中断优先级NVIC_InitStructure.NVIC_IRQChannel MD_MASTER_USART_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority 1;NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);//最后配置485发送和接收模式MD_MASTER_TX_EN_CLK_FUN(MD_MASTER_TX_EN_CLK, ENABLE);//GPIOG.9GPIO_InitStructure.GPIO_Pin MD_MASTER_TX_EN_PIN; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP;GPIO_Init(MD_MASTER_TX_EN_PORT, GPIO_InitStructure); }void mb_port_uartEnable(uint8_t txen,uint8_t rxen) {if(txen){//使能发送完成中断USART_ITConfig(MD_MASTER_USART, USART_IT_TC, ENABLE); //MAX485操作 高电平为发送模式GPIO_SetBits(MD_MASTER_TX_EN_PORT,MD_MASTER_TX_EN_PIN); }else{//禁止发送完成中断USART_ITConfig(MD_MASTER_USART, USART_IT_TC, DISABLE);//MAX485操作 低电平为接收模式GPIO_ResetBits(MD_MASTER_TX_EN_PORT,MD_MASTER_TX_EN_PIN);}if(rxen){//使能接收和接收中断USART_ITConfig(MD_MASTER_USART, USART_IT_RXNE, ENABLE);//MAX485操作 低电平为接收模式GPIO_ResetBits(MD_MASTER_TX_EN_PORT,MD_MASTER_TX_EN_PIN);}else{USART_ITConfig(MD_MASTER_USART, USART_IT_RXNE, DISABLE); //MAX485操作 高电平为发送模式GPIO_SetBits(MD_MASTER_TX_EN_PORT,MD_MASTER_TX_EN_PIN);} } void mb_port_putchar(uint8_t ch) { // huart1.Instance-DR ch; //直接操作寄存器比HAL封装的更高效//发送数据USART_SendData(MD_MASTER_USART, ch);while(USART_GetFlagStatus(MD_MASTER_USART,USART_FLAG_TXE) RESET){};//等待发送完成 }void mb_port_getchar(uint8_t *ch) { // *ch (uint8_t)(huart1.Instance-DR (uint8_t)0x00FF); *ch (uint8_t)(USART_ReceiveData(MD_MASTER_USART)); }void mb_port_timerInit(uint32_t baud) {/*定时器部分初始化*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;// uint16_t PrescalerValue 0;//使能定时器4时钟MD_MASTER_TIM_CLK_FUN(MD_MASTER_TIM_CLK, ENABLE);//定时器时间基配置说明//HCLK为72MHzAPB1经过2分频为36MHz//MD_MASTER_TIM的时钟倍频后为72MHz硬件自动倍频,达到最大//MD_MASTER_TIM的分频系数为3599时间基频率为72 / (1 Prescaler) 20KHz,基准为50us//TIM最大计数值为usTim1Timerout50u// PrescalerValue (uint16_t) (SystemCoreClock / 20000) - 1; //定时器1初始化/* If baudrate 19200 then we should use the fixed timer values* t35 1750us. Otherwise t35 must be 3.5 times the character time.*/if(baud19200) //波特率大于19200固定使用1800作为3.5T{TIM_TimeBaseStructure.TIM_Period 35;}else //其他波特率的需要根据计算{/* The timer reload value for a character is given by:** ChTimeValue Ticks_per_1s / ( baud / 11 )* 11 * Ticks_per_1s / baud* 220000 / baud* The reload for t3.5 is 1.5 times this value and similary* for t3.5.*/TIM_TimeBaseStructure.TIM_Period (uint32_t)(( 7UL * 220000UL ) / ( 2UL * baud ));} // TIM_TimeBaseStructure.TIM_Period RS485_Frame_Distance*10;TIM_TimeBaseStructure.TIM_Prescaler (uint16_t) (SystemCoreClock / 20000) - 1;//20KHZTIM_TimeBaseStructure.TIM_ClockDivision 0;TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up;TIM_TimeBaseInit(MD_MASTER_TIM, TIM_TimeBaseStructure);//预装载使能TIM_ARRPreloadConfig(MD_MASTER_TIM, ENABLE);//定时器4中断优先级NVIC_InitStructure.NVIC_IRQChannel MD_MASTER_TIM_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority 2;NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);//清除溢出中断标志位TIM_ClearITPendingBit(MD_MASTER_TIM,TIM_IT_Update);//定时器4溢出中断关闭TIM_ITConfig(MD_MASTER_TIM, TIM_IT_Update, DISABLE);//定时器4禁能TIM_Cmd(MD_MASTER_TIM, DISABLE); }void mb_port_timerEnable() {TIM_ClearITPendingBit(MD_MASTER_TIM, TIM_IT_Update);TIM_ITConfig(MD_MASTER_TIM, TIM_IT_Update, ENABLE);//设定定时器4的初始值TIM_SetCounter(MD_MASTER_TIM,0x0000); //定时器4启动TIM_Cmd(MD_MASTER_TIM, ENABLE); }void mb_port_timerDisable() {TIM_ClearITPendingBit(MD_MASTER_TIM, TIM_IT_Update);TIM_ITConfig(MD_MASTER_TIM, TIM_IT_Update, DISABLE);TIM_SetCounter(MD_MASTER_TIM,0x0000); //关闭定时器4TIM_Cmd(MD_MASTER_TIM, DISABLE); } void mb_port_timerReset(void) {TIM_SetCounter(MD_MASTER_TIM,0x0000); } //串口中断服务函数 void MD_MASTER_USART_IRQHandler() {//发生接收中断if(USART_GetITStatus(MD_MASTER_USART, USART_IT_RXNE) SET){//清除中断标志位 USART_ClearITPendingBit(MD_MASTER_USART, USART_IT_RXNE); mbh_uartRxIsr();}//发生完成中断if(USART_GetITStatus(MD_MASTER_USART, USART_IT_TC) SET){//清除中断标志USART_ClearITPendingBit(MD_MASTER_USART, USART_IT_TC);mbh_uartTxIsr();} }//定时器中断服务函数 void MD_MASTER_TIM_IRQHandler() {if (TIM_GetITStatus(MD_MASTER_TIM, TIM_IT_Update) ! RESET){//清除定时器T4溢出中断标志位TIM_ClearITPendingBit(MD_MASTER_TIM, TIM_IT_Update);mbh_timer3T5Isr();} }mb_hook.c内需要添加各个功能码回调处理函数以及错误处理 /*** brief MODBUS主机模式下接收到从机回复不同功能码的回调处理* param add:从机的地址* param data:接收到的从机发来的数据指针* param datalen:接收到的从机发来的数据长度* return NONE* note rec01\02\03……等数字代表功能码*/ void mbh_hook_rec01(uint8_t add,uint8_t *data,uint8_t datalen); void mbh_hook_rec02(uint8_t add,uint8_t *data,uint8_t datalen); void mbh_hook_rec03(uint8_t add,uint8_t *data,uint8_t datalen); void mbh_hook_rec04(uint8_t add,uint8_t *data,uint8_t datalen); void mbh_hook_rec05(uint8_t add,uint8_t *data,uint8_t datalen); void mbh_hook_rec06(uint8_t add,uint8_t *data,uint8_t datalen); void mbh_hook_rec15(uint8_t add,uint8_t *data,uint8_t datalen); void mbh_hook_rec16(uint8_t add,uint8_t *data,uint8_t datalen); /*** brief MODBUS主机读写从机超过最大错误次数回调* param add:从机的地址* param cmd:功能码* return NONE* note */ void mbh_hook_timesErr(uint8_t add,uint8_t cmd);这里参考openedv论坛那位大哥的代码编写各个函数的实现逻辑需要注意的是freemodbus的开关与线圈是用位来表示的这位老哥的是单个数组元素表示一个位为了与freemodbus兼容这里也改成单个位表示一个字节表示8位。 //线圈状态 uint8_t ucRegCoilsBuf[REG_COILS_SIZE/8 ] {0x11,0xEF}; //开关输入状态 uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE/8 ] {0x00,0x00};为了与freemodbus兼容参考freemodbus源码内对数组单个位操作的函数并移植到这里mb_hook.c全部代码 #include mb_include.h 这里使用了宏定义来方便修改主机使用的数据方便主从机移植。 /***************主机寄存器宏定义***************/ #define M_CoilsRegBuf ucRegCoilsBuf #define M_DiscreteRegBuf ucRegDiscreteBuf #define M_HoldingRegBuf usRegHoldingBuf #define M_InputRegBuf usRegInputBuf /*********************************************/uint16_t SaveStartAddr 0; //数据保存起始地址 uint16_t DataORLenth 24; //数据长度 在写单个线圈寄存器时代表值 uint8_t MD_MASTER_ComErr 8; //0代表通讯正常#define BITS_UINT8_T 8U /* ucByteBuf位存储的缓冲区。必须是2个字节。usBitOffset: 位设置的起始地址第一个位的偏移为0。ucNBits: 需要修改的位的数量。该值必须小于8。ucValue 位的新值。在usBitOffset中的第一位的值是ucValues的最低有效位。 */ /* ----------------------- Start implementation -----------------------------*/ void MBSetBits( uint8_t * ucByteBuf, uint16_t usBitOffset, uint8_t ucNBits,uint8_t ucValue ) {uint16_t usWordBuf;uint16_t usMask;uint16_t usByteOffset;uint16_t usNPreBits;uint16_t usValue ucValue;// assert( ucNBits 8 ); // assert( ( size_t )BITS_UINT8_T sizeof( uint8_t ) * 8 );/* Calculate byte offset for first byte containing the bit values starting* at usBitOffset. */usByteOffset ( uint16_t )( ( usBitOffset ) / BITS_UINT8_T );/* How many bits precede our bits to set. */usNPreBits ( uint16_t )( usBitOffset - usByteOffset * BITS_UINT8_T );/* Move bit field into position over bits to set */usValue usNPreBits;/* Prepare a mask for setting the new bits. */usMask ( uint16_t )( ( 1 ( uint16_t ) ucNBits ) - 1 );usMask usBitOffset - usByteOffset * BITS_UINT8_T;/* copy bits into temporary storage. */usWordBuf ucByteBuf[usByteOffset];usWordBuf | ucByteBuf[usByteOffset 1] BITS_UINT8_T;/* Zero out bit field bits and then or value bits into them. */usWordBuf ( uint16_t )( ( usWordBuf ( ~usMask ) ) | usValue );/* move bits back into storage */ucByteBuf[usByteOffset] ( uint8_t )( usWordBuf 0xFF );ucByteBuf[usByteOffset 1] ( uint8_t )( usWordBuf BITS_UINT8_T ); } /* ucByteBuf位存储的缓冲区。必须是2个字节。usBitOffset: 位设置的起始地址第一个位的偏移为0。ucNBits: 需要修改的位的数量。该值必须小于8。 */ uint8_t MBGetBits( uint8_t * ucByteBuf, uint16_t usBitOffset, uint8_t ucNBits ) {uint16_t usWordBuf;uint16_t usMask;uint16_t usByteOffset;uint16_t usNPreBits;/* Calculate byte offset for first byte containing the bit values starting* at usBitOffset. */usByteOffset ( uint16_t )( ( usBitOffset ) / BITS_UINT8_T );/* How many bits precede our bits to set. */usNPreBits ( uint16_t )( usBitOffset - usByteOffset * BITS_UINT8_T );/* Prepare a mask for setting the new bits. */usMask ( uint16_t )( ( 1 ( uint16_t ) ucNBits ) - 1 );/* copy bits into temporary storage. */usWordBuf ucByteBuf[usByteOffset];usWordBuf | ucByteBuf[usByteOffset 1] BITS_UINT8_T;/* throw away unneeded bits. */usWordBuf usNPreBits;/* mask away bits above the requested bitfield. */usWordBuf usMask;return ( uint8_t ) usWordBuf; }//data[0] 返回的字节数 data[1]~[X]数据 void mbh_hook_rec01(uint8_t add, uint8_t *data, uint8_t datalen) { // uint16_t i;//寄存器个数int16_t Coils DataORLenth;//寄存器偏移量uint16_t BitOffsetSaveStartAddr;if ((SaveStartAddr DataORLenth) REG_COILS_SIZE) //寄存器地址数量在范围内{ // for (i 0; i DataORLenth; i) // { // M_CoilsRegBuf[SaveStartAddr i] data[1 i / 8] 0x01; //低位先发送 // data[1 i / 8] 1; // }data;while( Coils 0 ){MBSetBits( M_CoilsRegBuf, BitOffset,( uint8_t )( Coils 8 ? 8 : Coils ),*data );Coils - 8;BitOffset 8;}MD_MASTER_ComErr 0;}else{MD_MASTER_ComErr 255;} } void mbh_hook_rec02(uint8_t add, uint8_t *data, uint8_t datalen) { // uint16_t i;//寄存器个数int16_t Coils DataORLenth;//寄存器偏移量uint16_t BitOffsetSaveStartAddr;if ((SaveStartAddr DataORLenth) REG_DISCRETE_SIZE) //寄存器地址数量在范围内{ // for (i 0; i DataORLenth; i) // { // M_DiscreteRegBuf[SaveStartAddr i] data[1 i / 8] 0x01; //低位先发送 // data[1 i / 8] 1; // }data;while( Coils 0 ){MBSetBits( M_DiscreteRegBuf, BitOffset,( uint8_t )( Coils 8 ? 8 : Coils ),*data );Coils - 8;BitOffset 8;}MD_MASTER_ComErr 0;}else{MD_MASTER_ComErr 255;} } void mbh_hook_rec03(uint8_t add, uint8_t *data, uint8_t datalen) {uint8_t i;uint8_t RegNum;RegNum data[0] / 2; //获取字节数if ((SaveStartAddr RegNum) 1000) //寄存器地址数量在范围内{for (i 0; i RegNum; i){M_HoldingRegBuf[SaveStartAddr i] data[1 i * 2]; /高8位M_HoldingRegBuf[SaveStartAddr i] data[2 i * 2] (M_HoldingRegBuf[SaveStartAddr i] 8); // 低8位高8位}MD_MASTER_ComErr 0;}else{MD_MASTER_ComErr 255;} } void mbh_hook_rec04(uint8_t add, uint8_t *data, uint8_t datalen) {uint8_t i;uint8_t RegNum;RegNum data[0] / 2; //获取字节数if ((SaveStartAddr RegNum) 1000) //寄存器地址数量在范围内{for (i 0; i RegNum; i){M_InputRegBuf[SaveStartAddr i] data[1 i * 2]; /高8位M_InputRegBuf[SaveStartAddr i] data[2 i * 2] (M_InputRegBuf[SaveStartAddr i] 8); // 低8位高8位}MD_MASTER_ComErr 0;}else{MD_MASTER_ComErr 255;} } void mbh_hook_rec05(uint8_t add, uint8_t *data, uint8_t datalen) {uint16_t i;i DataORLenth;if ((i 0 data[2] 0XFF data[3] 0X00) || (i 0 data[2] 0X00 data[3] 0X00)){MD_MASTER_ComErr 0;}else{MD_MASTER_ComErr 255;} } void mbh_hook_rec06(uint8_t add, uint8_t *data, uint8_t datalen) {uint16_t i; //数据返回校验用i (((uint16_t)data[2]) 8) | data[3]; //获取寄存器值if (i M_HoldingRegBuf[SaveStartAddr]){MD_MASTER_ComErr 0;}else{MD_MASTER_ComErr 255;} } void mbh_hook_rec15(uint8_t add, uint8_t *data, uint8_t datalen) {uint16_t i;//数据返回校验用i (((uint16_t)data[2]) 8) | data[3]; //获取寄存器数量if (i DataORLenth){MD_MASTER_ComErr 0;}else{MD_MASTER_ComErr 255;} } void mbh_hook_rec16(uint8_t add, uint8_t *data, uint8_t datalen) {uint16_t i;//数据返回校验用i (((uint16_t)data[2]) 8) | ((data[3])); //获取寄存器数量if (i DataORLenth){MD_MASTER_ComErr 0;}else{MD_MASTER_ComErr 255;} }//连续错误处理 void mbh_hook_timesErr(uint8_t add, uint8_t cmd) {mbHost.state MBH_STATE_IDLE;//状态切换为空闲MD_MASTER_ComErr 0; }我再连续出错里没有做什么处理只是将状态消除好继续下一个发送命令这里可以加入自己想要的处理。 在mb_host.c主要修改3个函数 /*** brief MODBUS主机给从机发送一条命令* param add:从机地址* param cmd:功能码* param start_address:数据起始地址* param data:要发送的数据* param len:发送的数据长度* return -1:发送失败 0:发送成功* note 该函数为非阻塞式调用后立即返回*/ int8_t mbh_send(uint8_t add,uint8_t cmd,uint16_t start_address,uint16_t *data,uint16_t data_len); 以及 void mbh_uartRxIsr(void); /*** brief modbus主机串口接收中断处理* return none* note 放在mcu的tx中断中调用* */ void mbh_uartTxIsr(void);修改主机命令发送函数 //发送一帧命令 int8_t mbh_send(uint8_t add, uint8_t cmd, uint16_t start_address, uint16_t *data, uint16_t data_len) {uint16_t crc;uint16_t temp 0;uint16_t i;int16_t Coils data_len;//偏移量uint16_t BitOffset start_address;uint8_t *data8_P (uint8_t *)data; //if (mbHost.state ! MBH_STATE_IDLE)return -1; //busy statembHost.txCounter 0;mbHost.rxCounter 0;mbHost.txBuf[0] add;mbHost.txBuf[1] cmd;mbHost.txBuf[2] HI(start_address);mbHost.txBuf[3] LOW(start_address);switch (cmd){case READ_COIL:case READ_DI:case READ_HLD_REG:case READ_AI:mbHost.txBuf[4] HI(data_len);mbHost.txBuf[5] LOW(data_len);break;case SET_COIL:if (DataORLenth)temp 0xFF00;else temp 0x0000;mbHost.txBuf[4] HI(temp);mbHost.txBuf[5] LOW(temp);break;case SET_HLD_REG:mbHost.txBuf[4] HI(data[start_address]);mbHost.txBuf[5] LOW(data[start_address]);break;case WRITE_COIL:temp 0;while (Coils 0){mbHost.txBuf[7 temp] MBGetBits(data8_P, BitOffset,(uint8_t)(Coils 8 ? 8 : Coils));Coils - 8;temp;BitOffset 8;}mbHost.txBuf[4] HI(data_len);mbHost.txBuf[5] LOW(data_len);mbHost.txBuf[6] temp;break;case WRITE_HLD_REG:temp 2 * data_len;for (i 0; i data_len; i){mbHost.txBuf[7 i * 2] data[start_address i] 8; //高字节在前mbHost.txBuf[8 i * 2] data[start_address i]; //低字节在后}mbHost.txBuf[4] HI(data_len);mbHost.txBuf[5] LOW(data_len);mbHost.txBuf[6] temp;break;}mbHost.txLen 6; //data_len(2)start_address(2)add(1)cmd(1)if (cmd WRITE_COIL || cmd WRITE_HLD_REG){mbHost.txLen temp 1; //mbHost.txLen7}crc mb_crc16(mbHost.txBuf, mbHost.txLen);mbHost.txBuf[mbHost.txLen] (uint8_t)(crc 0xff);mbHost.txBuf[mbHost.txLen] (uint8_t)(crc 8);mbHost.state MBH_STATE_TX;mb_port_uartEnable(1, 0); //enable tx,disable rx/*先发送一个byte触发TC中断*/mb_port_putchar(mbHost.txBuf[mbHost.txCounter]); //send first char,then enter tx isrreturn 0; }另外两个发送字节处理与接收字节处理 void mbh_uartRxIsr() {uint8_t ch;mb_port_getchar(ch);switch (mbHost.state){case MBH_STATE_TX_END:mbHost.rxCounter 0;mbHost.rxBuf[mbHost.rxCounter] ch;mbHost.state MBH_STATE_RX;mb_port_timerReset();//收到数据重新从0计数break;case MBH_STATE_RX:if (mbHost.rxCounter MBH_RTU_MAX_SIZE){mbHost.rxBuf[mbHost.rxCounter] ch;}mb_port_timerReset();//收到数据重新从0计数break;default: // mb_port_timerEnable();break;} } void mbh_uartTxIsr() {switch (mbHost.state){case MBH_STATE_TX:if (mbHost.txCounter mbHost.txLen) //全部发送完{mbHost.state MBH_STATE_TX_END;mb_port_uartEnable(0, 1); //disable tx,enable rxmbHost.rxTimeOut 0; //清除接收超时计数mb_port_timerEnable(); //open timer}else{mb_port_putchar(mbHost.txBuf[mbHost.txCounter]);}break;case MBH_STATE_TX_END:mb_port_uartEnable(0, 1); //disable tx,enable rx // mb_port_timerEnable(); //open timerbreak;} }在main函数中添加测试代码 int main(void) {uint8_t Tx_state 0x00;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组22位抢占优先级2位响应优先级mbh_init(9600, 0);SaveStartAddr 0;DataORLenth 9;mbh_send(1, READ_AI, 0, usRegInputBuf, DataORLenth);delay_init();while (1){mbh_poll();if (MD_MASTER_ComErr 0){MD_MASTER_ComErr255;delay_ms(1000);switch (Tx_state){case 0:mbh_send(1, WRITE_HLD_REG, 0, usRegInputBuf, DataORLenth);Tx_state;break;case 1:mbh_send(1, READ_DI, 0, (uint16_t *)ucRegDiscreteBuf, DataORLenth);Tx_state;break;case 2:mbh_send(1, WRITE_COIL, 0, (uint16_t *)ucRegDiscreteBuf, DataORLenth);Tx_state;break;case 3: // memset(ucRegCoilsBuf, 0, 2); //将数据清0mbh_send(1, READ_COIL, 0, (uint16_t *)ucRegCoilsBuf, DataORLenth);Tx_state;break;case 4:ucRegCoilsBuf[0]0xEF;mbh_send(1, WRITE_COIL, 0, (uint16_t *)ucRegCoilsBuf, DataORLenth);Tx_state;break;case 5:memset(usRegHoldingBuf, 0, 20); //将数据清0mbh_send(1, READ_HLD_REG, 0, usRegHoldingBuf, DataORLenth);Tx_state;break;case 6:usRegHoldingBuf[0]12345;mbh_send(1, WRITE_HLD_REG, 0, usRegHoldingBuf, DataORLenth);Tx_state;break;}}} }
http://www.tj-hxxt.cn/news/230704.html

相关文章:

  • 成都网站建设07fly网络维护管理
  • 织梦网站开发门户网站系统有哪些平台
  • 企业网站内容如何搭建单页网站 产品放哪
  • 注册域名网站asp网站开发心得体会
  • 上上海网站建设设计集团门户网站建设公司
  • 椒江网站建设578做网站wordpress需要的插件
  • 有关做内购的网站科学规划网页的做法是()
  • 视频网站后台登陆东莞常平嘉华学校
  • php网站源码带后台静态网站 搜索
  • 网站建设标志图怎么用自助网站
  • 网站建设cach目录陕西省住房与建设厅网站
  • 杭州seo网站优化公司石家庄网站建设公司怎么样
  • 龙华住房与建设局网站wordpress如何设置页面布局
  • 做门户网站用什么技术好wordpress安装的模板文件在哪
  • 赣州做网站的公司哪家好搜索引擎优化与推广技术
  • 网站建设方向网络教育
  • 百度网站适配代码黄骅市属于沧州吗
  • 旅游电子商务网站模板企业公司如何做网站
  • vs做的网站排版错位百度 网站改版了
  • 门户网站自查报告网页视频制作软件
  • 山东省交通厅建设网站建设银行etc官方网站
  • 网站平面图要怎么做建筑公司网站常用长尾词
  • 学做网站需要哪几本书小型网站开发费用
  • 网站搭建公司排行榜电脑去哪里建设网站
  • 帝国做的网站打开速度东莞建网站公司哪个好
  • 甘肃平凉建设局网站个人网站做什么好
  • wordpress登录后评论seo搜索引擎优化报价
  • 傻瓜式免费自助建站系统做书app下载网站
  • 全网网站建设优化做外贸推广的公司
  • 旅游网站开发与建设论文做海报的素材网站