welcom ! Handel home

顯示具有 STM32 M3 UART 標籤的文章。 顯示所有文章
顯示具有 STM32 M3 UART 標籤的文章。 顯示所有文章

2025年4月16日 星期三

freertos olimex-stm32-e407 micro-ROS code

 bash

mkdir -p ~/firmware_ws/src cd ~/firmware_ws git clone https://github.com/micro-ROS/micro_ros_setup src/micro_ros_setup rosdep update rosdep install --from-path src --ignore-src -y source /opt/ros/humble/setup.bash colcon build source install/local_setup.bash

當你執行指令:

bash
ros2 run micro_ros_setup create_firmware_ws.sh freertos olimex-stm32-e407

這會建立適用於 STM32F407(Olimex STM32-E407 開發板)+ FreeRTOS 的 micro-ROS 韌體專案,接下來需要進行的步驟如下:


✅ STM32F4 + micro-ROS firmware 編譯與燒錄流程


① 建立 Firmware 專案(你已完成)

bash
ros2 run micro_ros_setup create_firmware_ws.sh freertos olimex-stm32-e407

會產生以下結構於 firmware/ 目錄中:

objectivec
firmware/ ├── freertos_apps/ ← 可放 app.c(你的 micro-ROS 節點程式) ├── mcu_ws/ ← 編譯產出資料夾 ├── build/ ← CMake 檔案中繼產物 ├── firmware.mk ← 預設編譯流程 └── ...

② 自訂 micro-ROS 範例應用(修改 app.c)

你可以修改:

bash
#firmware/freertos_apps/apps/micro_ros_olinux_e407/app.c

bash
firmware/freertos_apps/microros_olimex_e407_extensions/app.c

範例:定時發佈一個 Topic:

c
#include <rcl/rcl.h> #include <std_msgs/msg/int32.h> void appMain(void *argument) { rcl_allocator_t allocator = rcl_get_default_allocator(); rclc_support_t support; rcl_node_t node; rcl_publisher_t publisher; std_msgs__msg__Int32 msg; rclc_support_init(&support, 0, NULL, &allocator); rcl_node_init_default(&node, "stm32_node", "", &support); rcl_publisher_init_default(&publisher, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32), "stm32_int32"); msg.data = 0; while (1) { rcl_publish(&publisher, &msg, NULL); msg.data++; HAL_Delay(1000); } }

③ 建構韌體

bash
ros2 run micro_ros_setup build_firmware.sh

這會自動呼叫 make 編譯 STM32 firmware,產出 .elf、.bin 等檔案於:

bash
firmware/build/firmware.elf firmware/build/firmware.bin

④ 燒錄韌體到 STM32F407 開發板

🧰 準備:

  • USB ↔ UART 轉接器或 ST-Link v2(看板子配置)

  • 安裝 STM32Flasher / openocd / st-flash 工具

🔥 使用 openocd(推薦)

1. 安裝 openocd

bash
sudo apt install openocd

2. 啟動燒錄

bash
cd firmware openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c "program build/firmware.elf verify reset exit"

⑤ 啟動 micro-ROS Agent 並連接

開啟 ROS2 主機(如 RPi 或 Docker):

bash
ros2 run micro_ros_agent micro_ros_agent serial --dev /dev/ttyUSB0

請根據實際接線修改為 /dev/ttyUSB0 或 /dev/ttyAMA0

成功會顯示:

arduino
[INFO] [agent]: Client connected

🧪 測試 ROS2 topic 傳輸

bash
ros2 topic list ros2 topic echo /stm32_int32

若 app.c 有建構 publisher,就會看到連續的資料輸出。


✅ 常見問題與檢查清單

問題檢查事項
Agent 沒有 Client connectedSTM32 韌體未成功上傳或 UART 接錯
無法看到 topicapp.c 是否正確設定 publisher?
燒錄失敗STM32 是否正確進入 boot 模式?
無法開機確認使用的是 Olimex E407 相容板子


2025年4月14日 星期一

RRC 控制板(STM32) 經由 UART 接入 micro-ROS Agent

 

將 RRC 控制板(STM32) 經由 UART 接入 micro-ROS Agent,在 ROS 2 中成為可接收 /cmd_vel 指令的底盤控制節點



📦 系統架構圖

csharp
[ROS 2 Host PC] | | /cmd_vel (Twist msg) | [micro-ROS Agent ←—— UART (USB-to-Serial)] | [STM32F407VET6 + FreeRTOS + RRC 控制程式] | └── 控制馬達轉動

🧱 1. 在 STM32 上建立 micro-ROS Node (FreeRTOS)

📁 micro-ROS 應用範例目錄:

bash
firmware/freertos_apps/micro_ros_app/ └── app.c ← 放置你的應用程式

📄 app.c:接收 /cmd_vel 並控制底盤

c
#include <rcl/rcl.h> #include <rclc/rclc.h> #include <geometry_msgs/msg/twist.h> #include "rmw_microros/rmw_microros.h" #include "differential_chassis.h" // 假設你用差速底盤 rcl_subscription_t cmd_vel_sub; geometry_msgs__msg__Twist cmd_vel_msg; void cmd_vel_callback(const void * msgin) { const geometry_msgs__msg__Twist * msg = (const geometry_msgs__msg__Twist *)msgin; float linear = msg->linear.x; float angular = msg->angular.z; // 呼叫 RRC 提供的底盤函式(以差速底盤為例) diff_chassis_move(linear * 1000, 0, angular * 1000); // 單位放大為 PWM } void appMain(void * arg) { rcl_allocator_t allocator = rcl_get_default_allocator(); rclc_support_t support; rcl_node_t node; rclc_executor_t executor; // 初始化 micro-ROS rclc_support_init(&support, 0, NULL, &allocator); rcl_node_init_default(&node, "rrc_chassis_node", "", &support); // 建立 /cmd_vel 訂閱 rcl_subscription_init_default( &cmd_vel_sub, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(geometry_msgs, msg, Twist), "cmd_vel"); rclc_executor_init(&executor, &support.context, 1, &allocator); rclc_executor_add_subscription(&executor, &cmd_vel_sub, &cmd_vel_msg, &cmd_vel_callback, ON_NEW_DATA); while (1) { rclc_executor_spin_some(&executor, RCL_MS_TO_NS(10)); vTaskDelay(pdMS_TO_TICKS(10)); } }

🔌 2. micro-ROS Transport 設定(使用 UART)

📄 platformio.ini 或 transport.c 裡設定 UART

c
#define RCC_USART_TX_PIN GPIO_PIN_2 // 假設使用 USART2 #define RCC_USART_RX_PIN GPIO_PIN_3 #define RCC_USART_INSTANCE USART2

📄 rmw_microros_transport.c

c
bool rmw_uros_platform_serial_open(...) { return stm32_uart_open("/dev/serial0", 115200); // 實際底層 API }

🖥️ 3. 在 ROS 2 主機上啟動 micro-ROS Agent

bash
# 連接 ttyACM0、USB 或 UART ros2 run micro_ros_agent micro_ros_agent serial --dev /dev/ttyACM0

成功時顯示:

less
[INFO] [micro_ros_agent]: Client connected [INFO] [micro_ros_agent]: Successfully negotiated

🚀 4. 測試 ROS 2 發送 /cmd_vel

bash
ros2 topic pub /cmd_vel geometry_msgs/Twist "{linear: {x: 0.2}, angular: {z: 0.5}}"

STM32 應該會根據這個資料來執行馬達控制。


🧩 5. 整合到 RRC 的程式架構

你只需把上面 cmd_vel_callback() 中的 diff_chassis_move() 換成你原本的馬達控制介面即可,保留 micro-ROS 接收指令功能。


📁 參考資料與工具

資源說明
micro-ROS setup tool用來建立 firmware
RMW Micro XRCE-DDSmicro-ROS 使用的底層通訊
ROS 2 Twist msg/cmd_vel 格式參考

✅ 結語

你現在可以讓 RRC 控制板成為一個「接收 ROS 2 /cmd_vel 指令的底盤控制器」,並保有原本 FreeRTOS + 馬達控制邏輯,具備更高擴展性!

如果你想我幫你整合:

  • ✅ FreeRTOS 工程樣板

  • ✅ micro-ROS + UART transport

  • ✅ 差速或 Ackermann 控制介面封裝

我可以直接幫你產生一份工程目錄結構與範例。要我幫你建嗎?😎

2014年7月1日 星期二

STM32 USART by DMA mode

STM32  USART by DMA mode 

前言:開始學USART+DMA的時候看到帖子《STM32 UART DMA實現未知數據長度接收》,覺得方法妙極了。此下出自此帖子——(整體的思路是這樣的,一開始設置好DMA接收,可以把緩衝區長度設置為幀最大長度,我們可以把RX連接到計時器的管腳輸入端,並且一開始設置輸入並且使能引腳下降沿中斷,當幀的第一個位元組發送時,因為起始位為低電平,空閒時UART為高電平,滿足條件,進入中斷,禁止中斷,並且在中斷中開啟計時器,該計時器工作在重定模式,上升沿重定,並且設置好計時器輸出比較值為超時時間,比如20ms,這樣,在傳輸後面位元組時,肯定會有高低電平出現,即便是傳輸的是0x00,0xFF,雖然UART資料區不變,但是都為1,或都為0,但是因為起始位為低電平,停止位是高電平,所以肯定會有上升沿,計時器會一直復位,輸出計時器的計數器一直到達不了輸出比較值,當一幀傳輸結束後,定時在最後一個位元組重定後,由於沒有資料繼續到達,無法重定,則計數器就能計到輸出比較值,這時發出中斷,在計時器中斷中可以計算出接收資料的長度,並且通知外部資料已經接收完畢。)

今天我在工作中調通了另一種USART+DMA接收未知數據長度的接收,使用的是USRAT空閒匯流排中斷接收,這種方法也在網站上比較多見,以前沒試過,今天才知道如此的爽,另外我使用DMA發送USART資料替代了以前的查詢法發送,發現更加爽了。其速度快了很多,尤其是在大量資料傳輸與發送的時候其優勢更加明顯。
我舉個例子:1、後臺資料->USART1-> USART2->其它設備,其它設備資料->USART2-> USART1->後臺,這兩個資料過程也可能同時進行。
2
、由於硬體的限制,USART1和USART2的傳輸串列傳輸速率不一樣,比如USART1使用GPRS通信,USART2使用短距離無線通訊;或者USART1使用乙太網通信,USART2使用485匯流排通信。
由於在寢室只有筆記型電腦,只有一個串口轉USB,沒辦法實現兩個串口之間的資料轉發了,只好實現串口各自的資料轉發。
現在我把我實現的過程簡單描述一下:
1
、        初始化設置:USART1_RX+DMA1_ Channel5,USART2_RX+DMA1_ Channel6,USART1_TX+DMA1_ Channel4,USART2_TX+DMA1_ Channel7(具體設置請看套裝程式)。
2
、        當資料發送給USART1接收完畢時候會引起USART1的串口匯流排中斷,計算DMA1_ Channel5記憶體陣列剩餘容量,得到接收的字元長度。將接收的字元複製給DMA1_ Channel4記憶體陣列,啟動DMA1_ Channel4通道傳輸資料,(傳輸完成需要關閉。)下一次資料接收可以在啟動DMA1_ Channel4時候就開始,不需要等待DMA1_ Channel4資料傳輸完成。但是上一次DMA1_ Channel4完成之前,不可以將資料複製給DMA1_ Channel4記憶體陣列,會沖掉以前資料。
3
、        USART2類同USART1。
呵呵,下麵貼程式:
             1.[  IO口定義:]
2.  void GPIO_Configuration(void)
3.  {
4.       GPIO_InitTypeDef GPIO_InitStructure;
5.       /* 第1步:打開GPIO和USART部件的時鐘 */
6.       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
7.            RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
8.            /* 第2步:將USART Tx的GPIO配置為推挽複用模式 */
9.            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
10.           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
11.           GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
12.           GPIO_Init(GPIOA, &GPIO_InitStructure);
13.           /* 第3步:將USART Rx的GPIO配置為浮空輸入模式
14.           由於CPU復位後,GPIO缺省都是浮空輸入模式,因此下面這個步驟不是必須的
15.           但是,我還是建議加上便於閱讀,並且防止其它地方修改了這個口線的設置參數
16.           */
17.           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
18.           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
19.           GPIO_Init(GPIOA, &GPIO_InitStructure);
20.         /* 第1步:打開GPIO和USART2部件的時鐘 */
21.    //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
22.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
23.         /* 第2步:將USART2 Tx的GPIO配置為推挽複用模式 */
24.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
25.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
26.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
27.         GPIO_Init(GPIOA, &GPIO_InitStructure);
28.         /* 第3步:將USART2 Rx的GPIO配置為浮空輸入模式
29.                 由於CPU復位後,GPIO缺省都是浮空輸入模式,因此下面這個步驟不是必須的
30.                 但是,我還是建議加上便於閱讀,並且防止其它地方修改了這個口線的設置參數
31.         */
32.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
33.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
34.         GPIO_Init(GPIOA, &GPIO_InitStructure);
35.         /*  第3步已經做了,因此這步可以不做
36.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
37.         */
38.         GPIO_Init(GPIOA, &GPIO_InitStructure);
39. }
40. [串口初始化:]
41. void USART_Configuration(void)
42. {
43.         USART_InitTypeDef USART_InitStructure;
44.           /* 第4步:配置USART參數
45.           - BaudRate = 115200 baud
46.           - Word Length = 8 Bits
47.           - One Stop Bit
48.           - No parity
49.           - Hardware flow control disabled (RTS and CTS signals)
50.           - Receive and transmit enabled
51.           */
52.           USART_InitStructure.USART_BaudRate = 19200;
53.           USART_InitStructure.USART_WordLength = USART_WordLength_8b;
54.           USART_InitStructure.USART_StopBits = USART_StopBits_1;
55.           USART_InitStructure.USART_Parity = USART_Parity_No;
56.           USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
57.           USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
58.           USART_Init(USART1, &USART_InitStructure);
59.           //空閒中斷
60.           USART_ITConfig(USART1, USART_IT_IDLE , ENABLE);
61.         /* 第5步:使能 USART, 配置完畢 */
62.           USART_Cmd(USART1, ENABLE);  
63.         /* CPU的小缺陷:串口配置好,如果直接Send,則第1個位元組發送不出去
64.           如下語句解決第1個位元組無法正確發送出去的問題 */
65.           USART_ClearFlag(USART1, USART_FLAG_TC); /* 清發送外城標誌,Transmission Complete flag */
66.         USART_InitStructure.USART_BaudRate = 9600;
67.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
68.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
69.         USART_InitStructure.USART_Parity = USART_Parity_No;
70.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
71.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
72.           USART_Init(USART2, &USART_InitStructure);
73.           USART_ITConfig(USART2, USART_IT_IDLE , ENABLE);//開啟空閒,幀錯,雜訊,校驗錯中斷 
74.         USART_Cmd(USART2, ENABLE);
75.         /* CPU的小缺陷:串口配置好,如果直接Send,則第1個位元組發送不出去
76.           如下語句解決第1個位元組無法正確發送出去的問題 */
77.           USART_ClearFlag(USART2, USART_FLAG_TC); /* 清發送外城標誌,Transmission Complete flag */
78. }
79.[ DMA配置:]
80. void DMA_Configuration(void)
81. {
82.   DMA_InitTypeDef DMA_InitStructure;
83.   /* DMA clock enable */
84.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1
85.   /* DMA1 Channel4 (triggered by USART1 Tx event) Config */
86.   DMA_DeInit(DMA1_Channel4);  
87.   DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;
88.   DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_SEND_DATA;
89.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
90.   DMA_InitStructure.DMA_BufferSize = 512;
91.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
92.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
93.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
94.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
95.   DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
96.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
97.   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
98.   DMA_Init(DMA1_Channel4, &DMA_InitStructure);
99.   DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
100.     DMA_ITConfig(DMA1_Channel4, DMA_IT_TE, ENABLE);
101.     /* Enable USART1 DMA TX request */
102.     USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
103.     DMA_Cmd(DMA1_Channel4, DISABLE);
104.     /* DMA1 Channel5 (triggered by USART2 Tx event) Config */
105.     DMA_DeInit(DMA1_Channel7);  
106.     DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;
107.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2_SEND_DATA;
108.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
109.     DMA_InitStructure.DMA_BufferSize = 512;
110.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
111.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
112.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
113.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
114.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
115.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;
116.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
117.     DMA_Init(DMA1_Channel7, &DMA_InitStructure);
118.     DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);
119.     DMA_ITConfig(DMA1_Channel7, DMA_IT_TE, ENABLE);
120.     /* Enable USART1 DMA TX request */
121.     USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
122.     DMA_Cmd(DMA1_Channel7, DISABLE);
123.     /* DMA1 Channel5 (triggered by USART1 Rx event) Config */
124.     DMA_DeInit(DMA1_Channel5);  
125.     DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;
126.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_RECEIVE_DATA;
127.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
128.     DMA_InitStructure.DMA_BufferSize = 512;
129.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
130.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
131.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
132.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
133.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
134.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;
135.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
136.     DMA_Init(DMA1_Channel5, &DMA_InitStructure);
137.     DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
138.     DMA_ITConfig(DMA1_Channel5, DMA_IT_TE, ENABLE);
139.     
140.     /* Enable USART1 DMA RX request */
141.     USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
142.     DMA_Cmd(DMA1_Channel5, ENABLE);
143.     /* DMA1 Channel6 (triggered by USART1 Rx event) Config */
144.     DMA_DeInit(DMA1_Channel6);  
145.     DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;
146.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2_RECEIVE_DATA;
147.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
148.     DMA_InitStructure.DMA_BufferSize = 512;
149.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
150.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
151.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
152.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
153.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
154.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
155.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
156.     DMA_Init(DMA1_Channel6, &DMA_InitStructure);
157.     DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
158.     DMA_ITConfig(DMA1_Channel6, DMA_IT_TE, ENABLE);
159.     /* Enable USART2 DMA RX request */
160.     USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
161.     DMA_Cmd(DMA1_Channel6, ENABLE);
162.   }
163. [ 中斷優先順序配置:]
164.   void NVIC_Configuration(void)
165.   {
166.     NVIC_InitTypeDef NVIC_InitStructure;
167.     /* Configure one bit for preemption priority */
168.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  
169.     /* Enable the USART1 Interrupt */
170.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
171.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
172.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
173.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
174.     NVIC_Init(&NVIC_InitStructure);
175.     /* Enable the USART2 Interrupt */
176.     NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
177.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
178.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
179.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
180.     NVIC_Init(&NVIC_InitStructure);
181.     //Enable DMA Channel4 Interrupt 
182.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
183.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
184.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
185.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
186.     NVIC_Init(&NVIC_InitStructure);
187.     //Enable DMA Channel7 Interrupt 
188.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;
189.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
190.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
191.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
192.     NVIC_Init(&NVIC_InitStructure);
193.     /*Enable DMA Channel5 Interrupt */
194.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
195.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
196.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
197.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
198.     NVIC_Init(&NVIC_InitStructure);
199.     /*Enable DMA Channel6 Interrupt */
200.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
201.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
202.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
203.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
204.     NVIC_Init(&NVIC_InitStructure);
205.   }
206.   陣列定義,含義如題名:
207.   u8 USART1_SEND_DATA[512];     
208.   u8 USART2_SEND_DATA[512]; 
209.   u8 USART1_RECEIVE_DATA[512]; 
210.   u8 USART2_RECEIVE_DATA[512]; 
211.   u8 USART1_TX_Finish=1;// USART1發送完成標誌量
212.   u8 USART2_TX_Finish=1; // USART2發送完成標誌量
213. [  USART1中斷服務函數]
214.   void USART1_IRQHandler(void)
215.   {
216.           u16 DATA_LEN;
217.           u16 i;
218.           if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)//如果為空閒匯流排中斷
219.       {
220.                   DMA_Cmd(DMA1_Channel5, DISABLE);//關閉DMA,防止處理其間有資料
221.                   //USART_RX_STA = USART1->SR;//先讀SR,然後讀DR才能清除
222.           //USART_RX_STA = USART1->DR;
223.                     DATA_LEN=512-DMA_GetCurrDataCounter(DMA1_Channel5); 
224.                   if(DATA_LEN > 0)
225.           {                        
226.                           while(USART1_TX_Finish==0)//等待資料傳輸完成才下一次
227.               {
228.                   ;
229.               }
230.                           //將資料送DMA存儲位址
231.               for(i=0;i
232.               {
233.                   USART1_SEND_DATA[i]=USART1_RECEIVE_DATA[i];
234.               }
235.               //USART用DMA傳輸替代查詢方式發送,克服被高優先順序中斷而產生丟幀現象。
236.               DMA_Cmd(DMA1_Channel4, DISABLE); //改變datasize前先要禁止通道工作
237.               DMA1_Channel4->CNDTR=DATA_LEN; //DMA1,傳輸資料量
238.               USART1_TX_Finish=0;//DMA傳輸開始標誌量
239.               DMA_Cmd(DMA1_Channel4, ENABLE);                        
240.                   }
241.                   //DMA_Cmd(DMA1_Channel5, DISABLE);//關閉DMA,防止處理其間有資料
242.                   DMA_ClearFlag(DMA1_FLAG_GL5 | DMA1_FLAG_TC5 | DMA1_FLAG_TE5 | DMA1_FLAG_HT5);//清標誌
243.                   DMA1_Channel5->CNDTR = 512;//重裝填
244.                   DMA_Cmd(DMA1_Channel5, ENABLE);//處理完,重開DMA
245.                   //讀SR後讀DR清除Idle
246.                   i = USART1->SR;
247.                   i = USART1->DR;
248.           }
249.           if(USART_GetITStatus(USART1, USART_IT_PE | USART_IT_FE | USART_IT_NE) != RESET)//出錯
250.           {
251.                   USART_ClearITPendingBit(USART1, USART_IT_PE | USART_IT_FE | USART_IT_NE);
252.           }
253.             USART_ClearITPendingBit(USART1, USART_IT_TC);
254.             USART_ClearITPendingBit(USART1, USART_IT_IDLE);
255.   }
256.   [USART2中斷服務函數]
257.   void USART2_IRQHandler(void)
258.   {
259.           u16 DATA_LEN;
260.           u16 i;
261.           if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) //如果為空閒匯流排中斷
262.       {
263.                   DMA_Cmd(DMA1_Channel6, DISABLE);//關閉DMA,防止處理其間有資料
264.                   //USART_RX_STA = USART1->SR;//先讀SR,然後讀DR才能清除
265.           //USART_RX_STA = USART1->DR;
266.                     DATA_LEN=512-DMA_GetCurrDataCounter(DMA1_Channel6); 
267.                   if(DATA_LEN > 0)
268.           {                        
269.                           while(USART2_TX_Finish==0)//等待資料完成才下一次
270.               {
271.                   ;
272.               }
273.                           //將資料送DMA存儲位址
274.               for(i=0;i
275.               {
276.                   USART2_SEND_DATA[i]=USART2_RECEIVE_DATA[i];
277.               }
278.               //USART用DMA傳輸替代查詢方式發送,克服被高優先順序中斷而產生丟幀現象。
279.               DMA_Cmd(DMA1_Channel7, DISABLE); //改變datasize前先要禁止通道工作
280.               DMA1_Channel7->CNDTR=DATA_LEN; //DMA1,傳輸資料量
281.               USART2_TX_Finish=0;//DMA傳輸開始標誌量
282.               DMA_Cmd(DMA1_Channel7, ENABLE);                        
283.                   }
284.                   //DMA_Cmd(DMA1_Channel5, DISABLE);//關閉DMA,防止處理其間有資料
285.                   DMA_ClearFlag(DMA1_FLAG_GL6 | DMA1_FLAG_TC6 | DMA1_FLAG_TE6 | DMA1_FLAG_HT6);//清標誌
286.                   DMA1_Channel6->CNDTR = 512;//重裝填
287.                   DMA_Cmd(DMA1_Channel6, ENABLE);//處理完,重開DMA
288.                   //讀SR後讀DR清除Idle
289.                   i = USART2->SR;
290.                   i = USART2->DR;
291.           }
292.           if(USART_GetITStatus(USART2, USART_IT_PE | USART_IT_FE | USART_IT_NE) != RESET)//出錯
293.           {
294.                   USART_ClearITPendingBit(USART2, USART_IT_PE | USART_IT_FE | USART_IT_NE);
295.           }
296.             USART_ClearITPendingBit(USART2, USART_IT_TC);
297.             USART_ClearITPendingBit(USART2, USART_IT_IDLE);
298.   }
299.  [ DMA1_Channel5中斷服務函數]
300.   void DMA1_Channel5_IRQHandler(void)
301.   {
302.     DMA_ClearITPendingBit(DMA1_IT_TC5);
303.     DMA_ClearITPendingBit(DMA1_IT_TE5);
304.     DMA_Cmd(DMA1_Channel5, DISABLE);//關閉DMA,防止處理其間有資料
305.     DMA1_Channel5->CNDTR = 580;//重裝填
306.     DMA_Cmd(DMA1_Channel5, ENABLE);//處理完,重開DMA
307.   }
308.  [ DMA1_Channel6中斷服務函數 ]
309.   void DMA1_Channel6_IRQHandler(void)
310.   {
311.     DMA_ClearITPendingBit(DMA1_IT_TC6);
312.     DMA_ClearITPendingBit(DMA1_IT_TE6);
313.     DMA_Cmd(DMA1_Channel6, DISABLE);//關閉DMA,防止處理其間有資料
314.     DMA1_Channel6->CNDTR = 580;//重裝填
315.     DMA_Cmd(DMA1_Channel6, ENABLE);//處理完,重開DMA
316.   }
317.  [ DMA1_Channel4中斷服務函數 ]
318.   //USART1使用DMA發資料中斷服務程式
319.   void DMA1_Channel4_IRQHandler(void)
320.   {
321.     DMA_ClearITPendingBit(DMA1_IT_TC4);
322.     DMA_ClearITPendingBit(DMA1_IT_TE4);
323.     DMA_Cmd(DMA1_Channel4, DISABLE);//關閉DMA
324.     USART1_TX_Finish=1;//置DMA傳輸完成
325.   }

326. [  DMA1_Channel7中斷服務函數]
327.   //USART2使用DMA發資料中斷服務程式
328.   void DMA1_Channel7_IRQHandler(void)
329.   {
330.     DMA_ClearITPendingBit(DMA1_IT_TC7);
331.     DMA_ClearITPendingBit(DMA1_IT_TE7);
332.     DMA_Cmd(DMA1_Channel7, DISABLE);//關閉DMA
333.     USART2_TX_Finish=1;//置DMA傳輸完成
334.   }

複製代碼