这几天因为工作需要,移植了modbus RTU到STM32来,之前也听说过modbus,但是没有深入了解过,还以为会像usb 那样复杂的,经过这几天的折腾,发现真的太简单了。为了防止过段时间又忘记了怎么移植,在这里把移植过程记录下来,也为了方便初次接触modbus的人。
废话少说,首先去下载源码,我下载的是freemodbus-v1.5.0,解压后如图所示:
根据注释,可以知道vMBPortSerialEnable是串口发送和接收中断的控制的,包括发送中断和接收中断,在这里,我们用的是RXNE 和 TXE中断,代码如下:
[C] 纯文本查看 复制代码
?
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | voidvMBPortSerialEnable(BOOLxRxEnable,BOOLxTxEnable ) { if(TRUE==xRxEnable) { USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); } else { USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); } if(TRUE==xTxEnable) { USART_ITConfig(USART1, USART_IT_TXE, ENABLE); } else { USART_ITConfig(USART1, USART_IT_TXE, DISABLE); } } |
而 xMBPortSerialInit 函数显然是串口初始化的了,因为我在usart.c已经有一个串口初始化函数,这里直接调用该初始化函数usart_init(ulBaudRate);同时将return FALSE 改成 return TRUE; 注意这里我们只用了波特率这个参数,其他参数直接忽略,你也可以根据自己需要改一下。
然后 xMBPortSerialPutByte 和 xMBPortSerialGetByte 分别是发送和接收一个字节数据的函数,这里我直接调用库函数;
[C] 纯文本查看 复制代码
?
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 | BOOL xMBPortSerialPutByte(CHARucByte ) { USART_SendData(USART1, ucByte); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)/*????·????ê??*/ { } returnTRUE; } BOOL xMBPortSerialGetByte(CHAR* pucByte ) { *pucByte = USART_ReceiveData(USART1); returnTRUE; } |
最后还有两个中断处理函数,把前面的static 去掉,因为我不想把我的串口中断函数放到这个文件。然后我们在stm32f10x_it.c添加串口中断函数,如下:
[C] 纯文本查看 复制代码
?
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | voidUSART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) { prvvUARTRxISR(); USART_ClearITPendingBit(USART1, USART_IT_RXNE); } if(USART_GetITStatus(USART1, USART_IT_TXE) == SET) { prvvUARTTxReadyISR(); // USART_ClearITPendingBit(USART1, USART_IT_TXE); } } |
至此,portserial.c处理完毕。
porttimer.c的移植和portserial.c十分相似,但是要特别注意定时器中断的时间长度应该是3.5个字符时间,我这里只是简单粗暴的按照波特率是9600时候计算的。文件很短,直接上代码
[C] 纯文本查看 复制代码
?
01 02 03 04 05 06 07 08 09 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 | BOOL xMBPortTimersInit(USHORTusTim1Timerout50us ) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_DeInit(TIM2); #if 0 TIM_TimeBaseStructure.TIM_Period = 0x7E54; //CLK==24MHz ((1000000000/9600)*11*3.5)/(1000/24) == 0x7e54 TIM_TimeBaseStructure.TIM_Prescaler = 0x3; #endif // ?????????¤·?????????7200/72M = 0.0001,????100us????????1 //10us x 50 = 5ms,??5ms???????? TIM_TimeBaseStructure.TIM_Period = 50; TIM_TimeBaseStructure.TIM_Prescaler = (7200 - 1); TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_Cmd(TIM2, ENABLE); returnTRUE; } void vMBPortTimersEnable( ) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); TIM_SetCounter(TIM2, 0); //TIM_Cmd(TIM2, ENABLE); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); } void vMBPortTimersDisable( ) { TIM_SetCounter(TIM2, 0); //TIM_Cmd(TIM2, DISABLE); TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); } void TIMERExpiredISR(void) { (void)pxMBPortCBTimerExpired(); } |
同样,在stm32f10x_it.c添加定时器中断处理函数,
[C] 纯文本查看 复制代码
?
1 2 3 4 5 | voidTIM2_IRQHandler(void) { TIMERExpiredISR(); TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } |
然后,我们还需要自己写四个回调函数,分别是读输入寄存器函数、读写保持寄存器函数、读写线圈函数和读离散寄存器函数,一般只用读写保持寄存器函数即可,具体怎么实现可以参考demo文件夹里面众多的demo.c文件。
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』