当前位置:   article > 正文

【实验记录】使用Keil 5开发APM32F10x(C8T6)核心板程序[0](LED,USART,串口DMA接收)_keil安装apm32 pack包

keil安装apm32 pack包

实验目的

项目背景

希望做一款舵机复现手臂运动的桌面装置,分为穿戴端和桌面端。

穿戴端计划采用单片机收集2个陀螺仪数据,通过无线收发装置(验证版采用zigbee透传模块,后续考虑接入局域网控制)。

本实验目的为开发穿戴端的收发程序。

开发环境选择

网购了两块开发板,商家商品标注不明,实际使用的是国产的pin-to-pin兼容芯片。但这也导致难以使用Cube IDE进行开发(烧写会报错“ Could not verify ST device! Abort connection.”有教程进行跳过:ST-Link设备连接。 Could not verify ST device! Abort connection._error in final launch sequence: failed to start gd-CSDN博客)。不过笔者电脑未安装STM32 ST-LINK Utility,遂作罢。选择Keil 5开发。

实验过程

SDK安装

芯片是Geehy的,公司官网:珠海极海半导体有限公司 (geehy.com)

SDK下载地址:珠海极海半导体有限公司 | APM32F103系列 (geehy.com)(向下拉,选择APM32F10x_SDK 与 APM32F1xx_DFP Pack 下载,前者是代码库,后者是Keil Pack开发板资源)

芯片数据手册:APM32F103xC数据手册 V1.7.pdf (geehy.com)

我使用的不是官方推荐的APM32F103VC MINI开发板(使用手册:APM32F103VC MINI开发板使用说明书V1.1.pdf (geehy.com)),而是下面这款商品:https://m.tb.cn/h.gjxTn2heTm3fWv3?tk=d4Uo32ljgY6

实拍照片:

缺少部分外设,不过不影响使用官网软件开发包进行开发。

环境配置

先双击安装开发板资源。

为了节省时间,我选择直接基于部分例程(APM32F10x_SDK_V1.8\Examples\GPIO\GPIO_Toggle)进行开发。后续有时间自己再重走一遍。

程序烧写采用ST-LINK连接(菜单栏:Flash -> Configure Flash Tools... -> Debug -> 下图标注处,选择连接方式)。

代码编写

通过Keil 5打开项目文件夹APM32F10x_SDK_V1.8\Examples\GPIO\GPIO_Toggle\Project\MDK\GPIO_Toggle.uvprojx,进入项目编辑。

点灯(GPIO输出)

修改 Board_APM32F103_MINI.h 中的部分宏定义以适配开发板。开发板载LED(除电源指示LED)引脚PC13。找到相关代码,修改引脚(代码为修改后):

  1. /** @addtogroup APM32F103_MINI_LED
  2. * @{
  3. */
  4. #define LEDn 2
  5. #define LED2_PIN GPIO_PIN_13
  6. #define LED2_GPIO_PORT GPIOC
  7. #define LED2_GPIO_CLK RCM_APB2_PERIPH_GPIOC

然后就可以在main函数(所有#include "Board_APM32F103_MINI\inc\Board_APM32F103_MINI.h"的文件)中调用以下函数:

  1. void APM_MINI_LEDInit(Led_TypeDef Led);
  2. void APM_MINI_LEDOn(Led_TypeDef Led);
  3. void APM_MINI_LEDOff(Led_TypeDef Led);
  4. void APM_MINI_LEDToggle(Led_TypeDef Led);

操作LED2了。同样地,也可以将LED3重定义为某些与LED操作方式一致的外设。

串口回响

在打开DMA前,先实现串口回响(收什么发什么)。

新增文件uart_driver.h、uart_driver.c,撰写串口相关函数。注意新增的头文件要放入指定的文件夹(如本项目中的APM32F10x_SDK_V1.8\Examples\GPIO\GPIO_Toggle\Include),如果想自定义头文件需要自行添加目录(菜单栏:Flash -> Configure Flash Tools... -> C/C++ -> 下图标注处,添加路径)。

 在uart_driver.c中定义USART1的初始化函数、中断服务函数与收发函数:

  1. // 文件:uart_driver.c
  2. // 功能:串口回响
  3. #include <stdint.h>
  4. #include "apm32f10x_usart.h"
  5. // #include "apm32f10x_dma.h" //未开启DMA时不需要
  6. #include "Board_APM32F103_MINI\inc\Board_APM32F103_MINI.h"
  7. #include "uart_driver.h"
  8. // USART1 TEST 初始化
  9. // 非DMA版本
  10. void USART1_Init()
  11. {
  12. // 使用结构体初始化串口USART1
  13. USART_Config_T U1_Configer;
  14. U1_Configer.baudRate = 9600; // 波特率,9600
  15. U1_Configer.wordLength = USART_WORD_LEN_8B; // 数据位,8bit
  16. U1_Configer.stopBits = USART_STOP_BIT_1; // 停止位,1bit
  17. U1_Configer.parity = USART_PARITY_NONE; //校验位,0bit
  18. U1_Configer.mode = USART_MODE_TX_RX; // 模式,收发
  19. U1_Configer.hardwareFlow = USART_HARDWARE_FLOW_NONE; // 硬件流控制,无
  20. APM_MINI_COMInit(COM1, &U1_Configer); // 这是SDK自带的函数,包含GPIO初始化及串口设置
  21. __NVIC_EnableIRQ(USART1_IRQn); // 与STM32不同的函数
  22. USART_EnableInterrupt(USART1, USART_INT_RXBNE); // 开启串口1的接收缓冲区非空中断(RXBNE,与STM的RBNE不同)
  23. }
  24. //
  25. // USART1接收中断处理函数
  26. void USART1_IRQHandler(void)
  27. {
  28. if (USART_ReadIntFlag(USART1, USART_INT_RXBNE) != RESET)
  29. {
  30. // 读取接收到的数据
  31. uint16_t data[2] = {USART_RxData(USART1), 0};
  32. // 发送数据回显
  33. USART1_Send_Str(data);
  34. // 清除接收中断标志位
  35. USART_ClearIntFlag(USART1, USART_INT_RXBNE);
  36. // 重新开启中断
  37. USART_EnableInterrupt(USART1, USART_INT_RXBNE);
  38. }
  39. }
  40. //
  41. // 串口发送字符串函数
  42. void USART1_Send_Str(uint8_t* str)
  43. {
  44. uint8_t cnt = 0;
  45. while (*str && cnt <= USART1_TX_MAX_LEN) {
  46. cnt ++;
  47. USART_TxData(USART1, *str++);
  48. while (USART_ReadStatusFlag(USART1, USART_FLAG_TXC) == RESET) {
  49. // 等待发送完成
  50. }
  51. }
  52. }

在uart_driver.h文件中声明相关函数:

  1. // 文件:uart_driver.h
  2. // 功能:串口回响
  3. #ifndef _UART_DRIVER_H_
  4. #define _UART_DRIVER_H_
  5. #include "apm32f10x_usart.h"
  6. void USART1_Init(void);
  7. void USART1_IRQHandler(void);
  8. void USART1_Send_Str(uint8_t* str)
  9. #endif

main.c中#include "uart_driver.h",main函数:

  1. int main(void)
  2. {
  3. // ==================== 外设初始化 ====================
  4. APM_MINI_LEDInit(LED2);
  5. APM_MINI_LEDOff(LED2);
  6. USART1_Init();
  7. USART1_DMA_Init();
  8. while (1)
  9. {
  10. // ==================== 发送测试 ====================
  11. USART_TxData(USART1, 'X');
  12. Delay();
  13. }

测试效果:

串口DMA接收(常规发送)

实现与JY62的交互。该模块可通过串口以定频率(可调节,≤256Hz)持续发送数据帧,并可通过串口发送指令进行设置。详见:JY62产品资料 (yuque.com)

常规发送功能即可满足需求,接收功能有两种解决方案:(1)DMA接收定长数据:开启传输完成中断(DMA_INT_TC),每接收2个数据帧长度触发中断服务,进行数据帧截取与读取;(2)DMA接收不定长数据:开启串口空闲中断,每个数据帧之间中断触发中断服务,进行数据帧截取与读取。

这里先选择实现第一个方案,第二个后续找时间实现。根据资料,USART1 RX 对应的DMA通道为 DMA1 Channel5。在uart_driver.c中定义相关的初始化函数、中断服务函数与收发函数:

  1. // 文件:uart_driver.c
  2. // 功能:串口1 DMA定长消息接收
  3. #include <stdint.h>
  4. #include <stdio.h>
  5. // ================================================== Std Periph Driver ==================================================
  6. #include "apm32f10x_usart.h"
  7. #include "apm32f10x_dma.h"
  8. #include "apm32f10x_misc.h"
  9. #include "Board_APM32F103_MINI\inc\Board_APM32F103_MINI.h"
  10. #include "uart_driver.h"
  11. #include "pwm_driver.h"
  12. #include "jy62.h" // 我自己写的JY62消息解码程序头文件
  13. // MPU_frame_data数组就是上面这个文件定义的extern变量
  14. #include "main.h"
  15. uint8_t USART1_RX_Buffer[64] = {0};
  16. #define USART1_RX_BUFFER_SIZE 64
  17. #define USART1_TX_MAX_LEN 32
  18. // USART1 DMA接收 初始化
  19. void USART1_DMA_Init(void)
  20. {
  21. // 开启相关外设时钟
  22. RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA | RCM_APB2_PERIPH_GPIOA);
  23. RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);
  24. RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);
  25. // GPIO初始化
  26. GPIO_Config_T GPIO_configStruct;
  27. /* Configure USART Tx as alternate function push-pull */
  28. GPIO_configStruct.mode = GPIO_MODE_AF_PP;
  29. GPIO_configStruct.pin = GPIO_PIN_9;
  30. GPIO_configStruct.speed = GPIO_SPEED_50MHz;
  31. GPIO_Config(GPIOA, &GPIO_configStruct);
  32. /* Configure USART Rx as input floating */
  33. GPIO_configStruct.mode = GPIO_MODE_IN_FLOATING;
  34. GPIO_configStruct.pin = GPIO_PIN_10;
  35. GPIO_Config(GPIOB, &GPIO_configStruct);
  36. // 初始化串口USART1
  37. USART_Config_T U1_Configer;
  38. U1_Configer.baudRate = 9600; // 波特率,9600
  39. U1_Configer.wordLength = USART_WORD_LEN_8B; // 数据位,8bit
  40. U1_Configer.stopBits = USART_STOP_BIT_1; // 停止位,1bit
  41. U1_Configer.parity = USART_PARITY_NONE; //校验位,0bit
  42. U1_Configer.mode = USART_MODE_TX_RX; // 模式,收发
  43. U1_Configer.hardwareFlow = USART_HARDWARE_FLOW_NONE; // 硬件流控制,无
  44. /* USART configuration */
  45. USART_Config(USART1, &U1_Configer);
  46. /* Enable USART */
  47. USART_EnableRx(USART1);
  48. USART_EnableTx(USART1);
  49. USART_Enable(USART1);
  50. // 配置 DMA
  51. DMA_Config_T DMA_ConfigStructure;
  52. DMA_ConfigStructure.peripheralBaseAddr = (uint32_t)/*(USART1->DATA)*/ (&(USART1->DATA_B)); // 外设地址
  53. DMA_ConfigStructure.memoryBaseAddr = (uint32_t)USART1_RX_Buffer; // 内存地址
  54. DMA_ConfigStructure.dir = DMA_DIR_PERIPHERAL_SRC; // 外设作为数据源
  55. DMA_ConfigStructure.bufferSize = USART1_RX_BUFFER_SIZE; // 缓冲区大小
  56. DMA_ConfigStructure.peripheralInc = DMA_PERIPHERAL_INC_DISABLE; // 外设地址不增
  57. DMA_ConfigStructure.memoryInc = DMA_MEMORY_INC_ENABLE; // 内存地址增
  58. DMA_ConfigStructure.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_BYTE; // 外设数据宽度为8位
  59. DMA_ConfigStructure.memoryDataSize = DMA_MEMORY_DATA_SIZE_BYTE; // 内存数据宽度为8位
  60. DMA_ConfigStructure.loopMode = DMA_MODE_NORMAL; // 正常模式
  61. DMA_ConfigStructure.priority = DMA_PRIORITY_HIGH; // 高优先级
  62. DMA_ConfigStructure.M2M = DMA_M2MEN_DISABLE; // 禁用内存到内存传输
  63. DMA_Reset(DMA1_Channel5);
  64. DMA_Config(DMA1_Channel5, &DMA_ConfigStructure); // 初始化DMA1通道
  65. DMA_ConfigDataNumber(DMA1_Channel5, 22); // 设置传输数据长度
  66. // 配置 DMA 中断
  67. NVIC_EnableIRQRequest(DMA1_Channel5_IRQn, 0, 0); // 注册中断服务
  68. DMA_EnableInterrupt(DMA1_Channel5, DMA_INT_TC);
  69. // APM32的TC(transmit complete)中断相当于STM32的FTF(full transmit finish)中断
  70. // 这里注意不要把标志位 DMA1_FLAG_INT_TC5 和中断类型 DMA_INT_TC 搞混
  71. // 初始化后初次使能USART1 DMA接收
  72. USART_EnableDMA(USART1, USART_DMA_RX);
  73. DMA_Enable(DMA1_Channel5);
  74. USART1_DMA_Receive();
  75. }
  76. //
  77. // 重启USART1 DMA接收函数
  78. void USART1_DMA_Receive()
  79. {
  80. // 使能 DMA 通道
  81. DMA_ConfigDataNumber(DMA1_Channel5, 22);
  82. DMA_Enable(DMA1_Channel5);
  83. // 配置USART1的DMA接收
  84. USART_EnableDMA(USART1, USART_DMA_RX);
  85. }
  86. //
  87. // DMA接收中断处理函数
  88. void DMA1_Channel5_IRQHandler(void)
  89. {
  90. // 解码
  91. if(DMA_ReadIntFlag(DMA1_INT_FLAG_TC5))
  92. {
  93. // 清除中断标志
  94. DMA_ClearIntFlag(DMA1_INT_FLAG_TC5);
  95. // 去使能 DMA
  96. DMA_Disable(DMA1_Channel5);
  97. // 数据帧处理,从两数据帧长的接收信息中截取0x55开头的消息
  98. // 保证接收到,但牺牲了一半的数据频率
  99. uint8_t i = 0;
  100. while(i + 10 < 22 && USART1_RX_Buffer[i] != 0x55)
  101. { i++;}
  102. uint8_t ii = 0;
  103. for(ii = 0; ii<10;ii++)
  104. {
  105. MPU_frame_data[ii] = USART1_RX_Buffer[i + ii];
  106. }
  107. MPU_frame_dataRecord(); // from JY62.h
  108. // 重使能 DMA
  109. USART1_DMA_Receive();
  110. }
  111. }
  112. //
  113. // 串口1发送字符串函数
  114. void USART1_Send_Str(uint8_t* str)
  115. {
  116. uint8_t cnt = 0;
  117. while (*str && cnt <= USART1_TX_MAX_LEN) {
  118. cnt ++;
  119. USART_TxData(USART1, *str++);
  120. while (USART_ReadStatusFlag(USART1, USART_FLAG_TXC) == RESET) {
  121. // 等待发送完成
  122. }
  123. }
  124. }
  125. //

类似地在在uart_driver.h文件中声明相关函数。在main函数中加入数据回传、在中断服务函数中加入LED点亮函数,测试是否正常工作符合预期:

  1. // 文件:main.c
  2. // 函数:int main(void)
  3. // 功能:隔时发送距中断剩余传输字节数
  4. int main(void)
  5. {
  6. // ================================================== 外设初始化 ==================================================
  7. APM_MINI_LEDInit(LED2);
  8. APM_MINI_LEDOff(LED2);
  9. USART1_DMA_Init();
  10. while (1)
  11. {
  12. // ================================================== 收发测试 ==================================================
  13. // 测试DMA传输数据cnt剩余量,正常应随字节接收从22到1后重置为22
  14. sprintf(txt, " %d \n", DMA_ReadDataNumber(DMA1_Channel5));
  15. USART1_Send_Str(txt);
  16. Delay();
  17. }
  18. }

定时发送字节,测试效果如下,符合预期:

测试:隔时回传JY62姿态角

先仿照USART1的常规收发代码,初始化USART2作为数据回传串口。

  1. // 文件:uart_driver.c
  2. // 功能:串口1 DMA定长消息接收;串口2 常规收发,数据回传
  3. #include <stdint.h>
  4. #include <stdio.h>
  5. // ================================================== Std Periph Driver ==================================================
  6. #include "apm32f10x_usart.h"
  7. #include "apm32f10x_dma.h"
  8. #include "apm32f10x_misc.h"
  9. #include "Board_APM32F103_MINI\inc\Board_APM32F103_MINI.h"
  10. #include "uart_driver.h"
  11. #include "pwm_driver.h"
  12. #include "jy62.h"
  13. #include "main.h"
  14. uint8_t USART1_RX_Buffer[64] = {0};
  15. #define USART1_RX_BUFFER_SIZE 64
  16. #define USART1_TX_MAX_LEN 32
  17. #define USART2_TX_MAX_LEN 32
  18. // USART1 DMA接收 初始化
  19. void USART1_DMA_Init(void)
  20. {
  21. // 开启相关外设时钟
  22. RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA | RCM_APB2_PERIPH_GPIOA);
  23. RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);
  24. RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);
  25. // GPIO初始化
  26. GPIO_Config_T GPIO_configStruct;
  27. /* Configure USART Tx as alternate function push-pull */
  28. GPIO_configStruct.mode = GPIO_MODE_AF_PP;
  29. GPIO_configStruct.pin = GPIO_PIN_9;
  30. GPIO_configStruct.speed = GPIO_SPEED_50MHz;
  31. GPIO_Config(GPIOA, &GPIO_configStruct);
  32. /* Configure USART Rx as input floating */
  33. GPIO_configStruct.mode = GPIO_MODE_IN_FLOATING;
  34. GPIO_configStruct.pin = GPIO_PIN_10;
  35. GPIO_Config(GPIOB, &GPIO_configStruct);
  36. // 初始化串口USART1
  37. USART_Config_T U1_Configer;
  38. U1_Configer.baudRate = 9600; // 波特率,9600
  39. U1_Configer.wordLength = USART_WORD_LEN_8B; // 数据位,8bit
  40. U1_Configer.stopBits = USART_STOP_BIT_1; // 停止位,1bit
  41. U1_Configer.parity = USART_PARITY_NONE; //校验位,0bit
  42. U1_Configer.mode = USART_MODE_TX_RX; // 模式,收发
  43. U1_Configer.hardwareFlow = USART_HARDWARE_FLOW_NONE; // 硬件流控制,无
  44. /* USART configuration */
  45. USART_Config(USART1, &U1_Configer);
  46. /* Enable USART */
  47. USART_EnableRx(USART1);
  48. USART_EnableTx(USART1);
  49. USART_Enable(USART1);
  50. // 配置 DMA
  51. DMA_Config_T DMA_ConfigStructure;
  52. DMA_ConfigStructure.peripheralBaseAddr = (uint32_t)/*(USART1->DATA)*/ (&(USART1->DATA_B)); // 外设地址
  53. DMA_ConfigStructure.memoryBaseAddr = (uint32_t)USART1_RX_Buffer; // 内存地址
  54. DMA_ConfigStructure.dir = DMA_DIR_PERIPHERAL_SRC; // 外设作为数据源
  55. DMA_ConfigStructure.bufferSize = USART1_RX_BUFFER_SIZE; // 缓冲区大小
  56. DMA_ConfigStructure.peripheralInc = DMA_PERIPHERAL_INC_DISABLE; // 外设地址不增
  57. DMA_ConfigStructure.memoryInc = DMA_MEMORY_INC_ENABLE; // 内存地址增
  58. DMA_ConfigStructure.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_BYTE; // 外设数据宽度为8位
  59. DMA_ConfigStructure.memoryDataSize = DMA_MEMORY_DATA_SIZE_BYTE; // 内存数据宽度为8位
  60. DMA_ConfigStructure.loopMode = DMA_MODE_NORMAL; // 正常模式
  61. DMA_ConfigStructure.priority = DMA_PRIORITY_HIGH; // 高优先级
  62. DMA_ConfigStructure.M2M = DMA_M2MEN_DISABLE; // 禁用内存到内存传输
  63. DMA_Reset(DMA1_Channel5);
  64. DMA_Config(DMA1_Channel5, &DMA_ConfigStructure); // 初始化DMA1通道5
  65. DMA_ConfigDataNumber(DMA1_Channel5, 22);
  66. // 配置 DMA 中断
  67. NVIC_EnableIRQRequest(DMA1_Channel5_IRQn, 0, 0);
  68. DMA_EnableInterrupt(DMA1_Channel5, DMA_INT_TC);
  69. // 使能USART1 DMA接收
  70. USART_EnableDMA(USART1, USART_DMA_RX);
  71. DMA_Enable(DMA1_Channel5);
  72. USART1_DMA_Receive();
  73. }
  74. //
  75. // 重启USART1 DMA接收函数
  76. void USART1_DMA_Receive()
  77. {
  78. // 使能 DMA 通道
  79. DMA_ConfigDataNumber(DMA1_Channel5, 22);
  80. DMA_Enable(DMA1_Channel5);
  81. // 配置USART1的DMA接收
  82. USART_EnableDMA(USART1, USART_DMA_RX);
  83. }
  84. //
  85. // DMA接收中断处理函数
  86. void DMA1_Channel5_IRQHandler(void)
  87. {
  88. //debug
  89. APM_MINI_LEDOn(LED2);
  90. // 解码
  91. if(DMA_ReadIntFlag(DMA1_INT_FLAG_TC5))
  92. {
  93. // 清除中断标志
  94. DMA_ClearIntFlag(DMA1_INT_FLAG_TC5);
  95. // 去使能 DMA
  96. DMA_Disable(DMA1_Channel5);
  97. // 数据帧处理
  98. uint8_t i = 0;
  99. while(i + 10 < 22 && USART1_RX_Buffer[i] != 0x55)
  100. { i++;}
  101. uint8_t ii = 0;
  102. for(ii = 0; ii<11; ii++)
  103. {
  104. MPU_frame_data[ii] = USART1_RX_Buffer[i + ii];
  105. }
  106. MPU_frame_dataRecord();
  107. // 重使能 DMA
  108. USART1_DMA_Receive();
  109. }
  110. }
  111. //
  112. // 串口1发送字符串函数
  113. void USART1_Send_Str(uint8_t* str)
  114. {
  115. uint8_t cnt = 0;
  116. while (*str && cnt <= USART1_TX_MAX_LEN) {
  117. cnt ++;
  118. USART_TxData(USART1, *str++);
  119. while (USART_ReadStatusFlag(USART1, USART_FLAG_TXC) == RESET) {
  120. // 等待发送完成
  121. }
  122. }
  123. }
  124. //
  125. // USART2 初始化
  126. void USART2_Init()
  127. {
  128. // 使用结构体初始化串口USART2
  129. USART_Config_T U2_Configer;
  130. //NVIC_InitTypeDef NVIC_InitStructure;
  131. U2_Configer.baudRate = 9600; // 波特率,9600
  132. U2_Configer.wordLength = USART_WORD_LEN_8B; // 数据位,8bit
  133. U2_Configer.stopBits = USART_STOP_BIT_1; // 停止位,1bit
  134. U2_Configer.parity = USART_PARITY_NONE; //校验位,0bit
  135. U2_Configer.mode = USART_MODE_TX_RX; // 模式,收发
  136. U2_Configer.hardwareFlow = USART_HARDWARE_FLOW_NONE; // 硬件流控制,无
  137. APM_MINI_COMInit(COM2, &U2_Configer);
  138. NVIC_EnableIRQRequest(USART2_IRQn, 0, 0);
  139. USART_EnableInterrupt(USART2, USART_INT_RXBNE);
  140. }
  141. //
  142. // USART1接收中断服务函数
  143. void USART2_IRQHandler(void)
  144. {
  145. if (USART_ReadIntFlag(USART2, USART_INT_RXBNE) != RESET)
  146. {
  147. // 读取接收到的数据
  148. uint16_t data = USART_RxData(USART2);
  149. // 这里添加服务
  150. // 清除接收中断标志位
  151. USART_ClearIntFlag(USART2, USART_INT_RXBNE);
  152. // 重新开启中断
  153. USART_EnableInterrupt(USART2, USART_INT_RXBNE);
  154. }
  155. }
  156. //
  157. // 串口2发送字符串函数
  158. void USART2_Send_Str(uint8_t* str)
  159. {
  160. uint8_t cnt = 0;
  161. while (*str && cnt <= USART2_TX_MAX_LEN) {
  162. cnt ++;
  163. USART_TxData(USART2, *str++);
  164. while (USART_ReadStatusFlag(USART2, USART_FLAG_TXC) == RESET) {
  165. // 等待发送完成
  166. }
  167. }
  168. }
  169. //

main函数添加相关代码:

  1. // 文件:main.c
  2. // 函数:int main(void)
  3. // 功能:隔时回传JY62姿态角
  4. int main(void)
  5. {
  6. // ================================================== 外设初始化 ==================================================
  7. APM_MINI_LEDInit(LED2);
  8. APM_MINI_LEDOff(LED2);
  9. USART2_Init();
  10. USART1_DMA_Init();
  11. while (1)
  12. {
  13. // ================================================== 数据回传测试 ==================================================
  14. // 结构体来自jy62.h
  15. sprintf(txt, "r %f ", Angle.roll);
  16. USART2_Send_Str(txt);
  17. Delay();
  18. sprintf(txt, "p %f ", Angle.pitch);
  19. USART2_Send_Str(txt);
  20. Delay();
  21. sprintf(txt, "y %f ", Angle.yaw);
  22. USART2_Send_Str(txt);
  23. Delay();
  24. }
  25. }

实验效果:

实验总结

  • 熟悉了APM32F10x的开发环境配置与库文件定义
  • 复现了常规外设(GPIO,USART,DMA)操作
  • 完成了部分模块的驱动移植,为下一步开发做准备

下次实验计划进行定时器TMR与PWM输出的驱动,以实现呼吸灯与舵机控制

其他感想

第一次写博客,也是在对以往实验记录方式进行了反思之后做出的决定。以后会更多地把这些个人的小实验作线上记录,给自己一个动力,也希望能吸引到同好交流与指教。

APM32作为国产 Arm Cortex-M3 架构单片机的优秀代表之一,单片机性能不错,价格也比较实惠,对于个人开发者来说性价比良好。美中不足的是SDK提供的库文件与STM32的表述区别还是很多的,移植并没有那么容易;且部分注释仍然不够充足、清晰。不过充足的示例还是为学习提供了便利。以后会多考虑。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/1009016
推荐阅读
  

闽ICP备14008679号