使用Platformio平台的libopencm3开发框架来开发STM32G0,以下为FreeRTOS和FreeModbus库使用。
1 新建项目
建立freertos_modbus项目
在PIO的Home页面新建项目,项目名称freertos_modbus,选择开发板为 MonkeyPi_STM32_G070RB,开发框架选择libopencm3;
项目建立完成后在src目录下新建main.c主程序文件;
修改下载和调试方式,这里开发板使用的是DAPLink仿真器,因此修改platformio.ini文件如下:
1upload_protocol = cmsis-dap
2debug_tool = cmsis-dap
2 编写程序
直接在之前的FreeRTOS工程上进行添加;
2.1 添加 freeModbus 库
从git仓库下载源码: https://github.com/cwalter-at/freemodbus
将下载的源码中的mobus文件夹放置到工程的lib目录下,然后在modbus目录新建library.json文件,内容如下:
1{
2 "name": "FreeModbus",
3 "version": "master",
4 "repository":{
5 "type":"git",
6 "url":"https://github.com/cwalter-at/freemodbus"
7 },
8 "build": {
9 "flags": [
10 "-Iascii",
11 "-Ifunctions",
12 "-Iinclude",
13 "-Irtu",
14 "-Itcp"
15 ],
16 "srcFilter": [
17 "+"
18 ]
19 }
20}
然后从FreeModbus源码中的 demoBAREport中复制文件到工程的srcmodbus_port文件夹下,最后的文件夹结构如下:
2.2 移植
portevent:
1/* ----------------------- Modbus includes ----------------------------------*/
2#include "mb.h"
3#include "mbport.h"
4#include "FreeRTOS.h"
5#include "task.h"
6
7/* ----------------------- Variables ----------------------------------------*/
8static eMBEventType eQueuedEvent;
9static BOOL xEventInQueue;
10static uint32_t modbus_last_active_time = 0;
11
12uint32_t get_modbus_last_active_time(void)
13{
14 return modbus_last_active_time;
15}
16
17/* ----------------------- Start implementation -----------------------------*/
18BOOL
19xMBPortEventInit( void )
20{
21 xEventInQueue = FALSE;
22 return TRUE;
23}
24
25BOOL
26xMBPortEventPost( eMBEventType eEvent )
27{
28 xEventInQueue = TRUE;
29 eQueuedEvent = eEvent;
30
31 if (eEvent == EV_EXECUTE) {
32 modbus_last_active_time = xTaskGetTickCount();
33 }
34 return TRUE;
35}
36
37BOOL
38xMBPortEventGet( eMBEventType * eEvent )
39{
40 BOOL xEventHappened = FALSE;
41
42 if( xEventInQueue )
43 {
44 *eEvent = eQueuedEvent;
45 xEventInQueue = FALSE;
46 xEventHappened = TRUE;
47 }
48 return xEventHappened;
49}
portserial
这里使用RS485,因此需要对RS485使能端口进行配置,其他为串口的配置,然后在发送和接收中断时候调用modbus相关接口进行处理:
1#include "port.h"
2
3#include "FreeRTOS.h"
4#include "queue.h"
5
6#include 3/cm3/nvic.h>
7#include 3/stm32/usart.h>
8#include 3/stm32/rcc.h>
9#include 3/stm32/gpio.h>
10
11/* ----------------------- Modbus includes ----------------------------------*/
12#include "mb.h"
13#include "mbport.h"
14
15/* ----------------------- static functions ---------------------------------*/
16
17xQueueHandle uart_queue;
18
19#define RS485_1_CLOCK RCC_GPIOB
20#define RS485_1_EN_PORT GPIOB
21#define RS485_1_EN_PIN GPIO8
22
23static void rs485_delay(int n)
24{
25 while (--n) {
26 __asm__ volatile ("nop");
27 }
28}
29
30static inline void rs485_1_rx_mode(void)
31{
32 gpio_clear(RS485_1_EN_PORT, RS485_1_EN_PIN);
33}
34
35static inline void rs485_1_tx_mode(void)
36{
37 gpio_set(RS485_1_EN_PORT, RS485_1_EN_PIN);
38}
39
40static inline void rs485_gpio_init(void)
41{
42 rcc_periph_clock_enable(RS485_1_CLOCK);
43 gpio_mode_setup(RS485_1_EN_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_1_EN_PIN);
44
45 rs485_1_rx_mode();
46}
47
48/* ----------------------- Start implementation -----------------------------*/
49void
50vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
51{
52 /* If xRXEnable enable serial receive interrupts. If xTxENable enable
53 * transmitter empty interrupts.
54 */
55 if (xRxEnable) {
56 rs485_delay(10000);
57 rs485_1_rx_mode();
58 rs485_delay(10000);
59 usart_enable_rx_interrupt(USART1);
60 }
61 else {
62 usart_disable_rx_interrupt(USART1);
63 }
64
65 if (xTxEnable) {
66 rs485_delay(10000);
67 rs485_1_tx_mode();
68 rs485_delay(10000);
69 usart_enable_tx_interrupt(USART1);
70 }
71 else {
72 usart_disable_tx_interrupt(USART1);
73
74 }
75}
76
77BOOL
78xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
79{
80 nvic_enable_irq(NVIC_USART1_IRQ);
81
82 rcc_periph_clock_enable(RCC_GPIOB);
83 gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO7);
84 gpio_set_af(GPIOB, GPIO_AF0, GPIO6 | GPIO7);
85
86 rcc_periph_clock_enable(RCC_USART1);
87
88 /* Set up USART/UART parameters using the libopencm3 helper functions */
89 usart_set_baudrate(USART1, ulBaudRate);
90 usart_set_databits(USART1, ucDataBits);
91 usart_set_stopbits(USART1, USART_STOPBITS_1);
92 usart_set_mode(USART1, USART_MODE_TX_RX);
93
94 switch (eParity) {
95 case MB_PAR_ODD:
96 usart_set_parity(USART1, USART_PARITY_ODD);
97 break;
98 case MB_PAR_EVEN:
99 usart_set_parity(USART1, USART_PARITY_EVEN);
100 break;
101 default:
102 usart_set_parity(USART1, USART_PARITY_NONE);
103 break;
104 }
105
106 usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
107
108 usart_enable(USART1);
109
110 rs485_gpio_init();
111
112 return TRUE;
113}
114
115BOOL
116xMBPortSerialPutByte( CHAR ucByte )
117{
118
119 usart_send_blocking(USART1, (uint16_t) ucByte);
120
121 return TRUE;
122}
123
124BOOL
125xMBPortSerialGetByte( CHAR * pucByte )
126{
127 *pucByte = usart_recv(USART1);
128
129 return TRUE;
130}
131
132
133uint32_t uart1_isr, uart1_icr;
134
135void usart1_isr(void)
136{
137
138 /* Check if we were called because of RXNE. */
139 if (((USART_CR1(USART1) & USART_CR1_RXNEIE) != 0) &&
140 ((USART_ISR(USART1) & USART_ISR_RXNE) != 0)) {
141
142 /* Retrieve the data from the peripheral. */
143 // usart_recv(USART1);
144
145 pxMBFrameCBByteReceived();
146
147 }
148
149
150 /* Check if we were called because of TXE. */
151 if (((USART_CR1(USART1) & USART_CR1_TXEIE) != 0) &&
152 ((USART_ISR(USART1) & USART_ISR_TXE) != 0)) {
153
154 /* Put data into the transmit register. */
155 //usart_send(USART1, data);
156
157 pxMBFrameCBTransmitterEmpty();
158
159 }
160
161}
porttimer
1#include "port.h"
2
3#include
4#include
5#include
6
7/* ----------------------- Modbus includes ----------------------------------*/
8#include "mb.h"
9#include "mbport.h"
10
11/* ----------------------- static functions ---------------------------------*/
12static void prvvTIMERExpiredISR( void );
13
14/* ----------------------- Start implementation -----------------------------*/
15BOOL
16xMBPortTimersInit( USHORT usTim1Timerout50us )
17{
18 rcc_periph_clock_enable(RCC_TIM2);
19 nvic_enable_irq(NVIC_TIM2_IRQ);
20 rcc_periph_reset_pulse(RST_TIM2);
21
22 timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
23
24 timer_set_prescaler(TIM2, (rcc_apb1_frequency/ 20000));
25
26 timer_disable_preload(TIM2);
27 timer_continuous_mode(TIM2);
28
29 timer_set_period(TIM2, usTim1Timerout50us);
30 timer_enable_counter(TIM2);
31
32 timer_enable_irq(TIM2, TIM_DIER_UIE);
33
34 return TRUE;
35}
36
37
38inline void
39vMBPortTimersEnable( )
40{
41 timer_set_counter(TIM2, 0);
42 timer_enable_counter(TIM2);
43}
44
45inline void