当前位置:   article > 正文

普冉(PUYA)单片机开发笔记(1): UART通信_py32f003 开发环境

py32f003 开发环境

PY32F003 系列 MCU

国产 32 位 MCU 日渐风行。在新做的项目中,为了 Cost-down,考虑要用国产 MCU 替代进口货,如果可行,在单片机这一块,BOM 可以降低一块钱。近日在考虑普冉(PUYA)的32位MCU。由于板子上 MCU 所需功能较为单一,因此考虑使用入门级的一款 MCU 进行替代。最终选择了 PY32F003F18P。

  • 这个型号采用 TSSOP20 封装,PCB 占用面积比较小
  • 虽然配备的内核是 Cortex-M0+,但其工作频率高达 48MHz(下图简介中的 32MHz 工作频率好像是笔误),单周期乘除法,软浮点运算,估计运算速度是够用的
  • 存储器容量也较大,64KByte Flash 和 8KByte SRAM,代码足够装得下
  • UART 外设有两个,满足使用需求
  • 1个 ADC,具有10个通道,满足使用需求
  • 3个 DMA 通道,满足使用需求
  • 至少5个可用的 16 位定时器,满足使用需求

开发环境:硬件连接

网购了一块 PY32F003F18P 芯片组的开发板(很便宜,良心价),买回来后自己焊接了管脚排针和 SWD 排针,然后用上了 J-Link 仿真器,为 J-Link 仿真器配备了一个 JTAG-SWD 转接板,用四芯杜邦线连接开发板。开发板配备了两个跳线器,一个跳线器连接了 3V3_IN 和 3V3,这样子接可以使用 SWD 的 3.3V 电源,省去了从 Type-C 供电。另一个跳线器把 BOOT0 对地短路,使 MCU 可以从内部 FLASH 启动。BOOT0 是 PA14 管脚,很好找。为了做实验,还另外连接了开发板的 UART2 (PA1:TX,PA0:RX)接到 USB-UART 转接模块上,再连接到上位机。

开发板上的 SWD 排针是5芯的,JTAG-SWD 接了 4 根线,多出来的是 RST 信号线。估摸着这个 RST 线应该是不用接的,于是就不接先。至此,硬件连接就 OK 了。

开发环境:软件配置

使用 USART_IT 例程

购买开发板时带有 PUYA MCU 的资料下载地址,于是从指定的地址下载了 PUYA 的开发包。开发包中有芯片手册和例程。这里选择了 USART_IT 例程,选择这个例程里的 Keil 工程,直接用 Keil uVision 打开,如下图所示。

查看一下这个工程的 Option,如下图所示。需要注意的是这个工程还包含了和其它例程共用的程序,例如 BSP/py32f003xx_Start_Kit中的 .c 文件,这些文件的存储位置不在例程文件夹里。

Project Items 的截图如下,默认使用 ARM Compiler:ARMGCC。先不改这些,继续往下走。

导入 PY32F003 的 DFP Pack

在开始编译工程以前,需要导入 PY MCU 的 DFP pack,这个 pack 包含在了软件包中的 pack 文件夹里,使用 Pack Installer --> Import 进来。Import 完成后,在产品系列中选择 PY32F003x8就好了。Packs Installer 界面右侧的部件显示 DFP 是 “Up to date” 状态。其它的都不修改先,继续!

使用魔术棒配置Target Options

确认 Device 正确

检查 Target 选项

  • 设置 Xtal (外部晶振)的频率为 24MHz,和开发板保持一致
  • ARM Compiler:使用默认的 5.x 版本的编译器
  • Operation system:None
  • 选中 “Use MicroLIB”,这个选项会影响到 printf 的编码
  • 检查和确认 IROM1 和 IRAM1 的范围

检查和确认 C/C++ 选项

  • Define PY32F003x8 变量
  • 选中 C99
  • 选中 “One ELF Section per Function”
  • Include Path 和 Compile control string 不要修改

配置仿真器(Debug)

PY 文档中举例使用的 PY-LINK 仿真器,本例中使用的是 J-LINK,所以仿真器应做相应的修改。其它选项不做修改。

点击仿真器的 Setting,第一次运行时会得到一个错误对话框,提示 J-Link 不认识这颗 MCU,点击继续,选择 Cortex-M0+,继续,得到 J-Link 对 MCU 的识别参数如下图所示。

  • 把 SWD 的速度设置得低一点:1MHz,避免下载时的不可靠
  • Reset 设置成 Normal
  • 为了确保下载正确,勾选 “Verify Code Downloaded” 和 “Download to Flash”

  • Flash Download 选项卡选择 “Erase Sectors”(默认是 “Erase Full Chip”)
  • 检查 “RAM for Algorithm” 的值如图所示
  • 确认 “Programming Algorithm” 的值,Start 和 Size 值如图所示

  • Utility 选项卡中 “Use Debug Driver” 和 “Update Target before Debugging”

编译工程

点击 “LOAD” 键一键下载。第一次编译是成功的,但是会提示烧写失败,不要紧,再下载一次就成了。例程的功能如下:

  1. 设置 UART2 的参数为 115200/N/8/1
  2. 设置 UART2 为中断式无阻塞收发
  3. 启动后,从 UART2 发送 0x01 到 0x0C
  4. 回送每一次从 UART2 接收到的固定 12 个字节的字节流到对端

实验证明,运行是成功的。

重定向 printf

  1. 在 main.c 的 #include “main.h” 下一行添加 #include <stdio.h>
  2. /* Private user code 一节中增加 fputc 函数(参见后面的 main.c 代码)
  3. 编译时会出现错误,提示 fputc 函数在 py32f003xx_Start_Kit.c 中和 main.c 中重复定义了。打开 py32f003xx_Start_Kit.c 文件,把 fputc 函数注释掉。
  4. 重新编译下载,成功了。在上位机的 XCOM 中实现了预期的功能。

main.c 的完整代码

  1. #include "main.h"
  2. #include <stdio.h>
  3. /* Private define ------------------------------------------------------------*/
  4. /* Private variables ---------------------------------------------------------*/
  5. UART_HandleTypeDef UartHandle;
  6. uint8_t aTxBuffer[12] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', '\r', '\n'};
  7. uint8_t aRxBuffer[12] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  8. /* Private function prototypes -----------------------------------------------*/
  9. /* Private user code ---------------------------------------------------------*/
  10. /*
  11. * Redirect printf to Uart2 (UartHandle refers to USART2)
  12. */
  13. int fputc(int ch, FILE *f)
  14. {
  15. HAL_UART_Transmit(&UartHandle, (uint8_t *)(&ch), 1, 0xffff);
  16. return ch;
  17. }
  18. /* Private macro -------------------------------------------------------------*/
  19. /* Private function prototypes -----------------------------------------------*/
  20. void USART_Config(void);
  21. void Error_Handler(void);
  22. /********************************************************************************************************
  23. **函数信息 :void main(void)
  24. **功能描述 :main函数
  25. **输入参数 :
  26. **输出参数 :
  27. ** 备注 :
  28. ********************************************************************************************************/
  29. int main(void)
  30. {
  31. HAL_Init(); // systick初始化
  32. USART_Config(); // USART初始化
  33. printf("PY32F003F18P is ready.\r\n");
  34. HAL_Delay(500);
  35. /*通过中断方式发送数据*/
  36. if (HAL_UART_Transmit_IT(&UartHandle, (uint8_t *)aTxBuffer, 12) != HAL_OK)
  37. {
  38. Error_Handler();
  39. }
  40. while (1)
  41. {
  42. }
  43. }
  44. /********************************************************************************************************
  45. **函数信息 :void USART_Config(void)
  46. **功能描述 :USART初始化
  47. **输入参数 :
  48. **输出参数 :
  49. ** 备注 :
  50. ********************************************************************************************************/
  51. void USART_Config(void)
  52. {
  53. GPIO_InitTypeDef GPIO_InitStruct;
  54. //====================
  55. // USART2初始化
  56. //====================
  57. __HAL_RCC_USART2_CLK_ENABLE();
  58. __HAL_RCC_GPIOA_CLK_ENABLE();
  59. UartHandle.Instance = USART2;
  60. UartHandle.Init.BaudRate = 115200;
  61. UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
  62. UartHandle.Init.StopBits = UART_STOPBITS_1;
  63. UartHandle.Init.Parity = UART_PARITY_NONE;
  64. UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  65. UartHandle.Init.Mode = UART_MODE_TX_RX;
  66. if (HAL_UART_Init(&UartHandle) != HAL_OK)
  67. {
  68. Error_Handler();
  69. }
  70. /**USART2 GPIO Configuration
  71. PA0 ------> USART2_TX
  72. PA1 ------> USART2_RX
  73. */
  74. GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
  75. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  76. GPIO_InitStruct.Pull = GPIO_PULLUP;
  77. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  78. GPIO_InitStruct.Alternate = GPIO_AF9_USART2;
  79. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  80. /* 使能NVIC */
  81. HAL_NVIC_SetPriority(USART2_IRQn, 0, 1);
  82. HAL_NVIC_EnableIRQ(USART2_IRQn);
  83. }
  84. /********************************************************************************************************
  85. **函数信息 :Error_Handler(void)
  86. **功能描述 :错误执行函数
  87. **输入参数 :
  88. **输出参数 :
  89. ** 备注 :
  90. ********************************************************************************************************/
  91. void Error_Handler(void)
  92. {
  93. while (1)
  94. {
  95. }
  96. }
  97. /********************************************************************************************************
  98. **函数信息 :void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
  99. **功能描述 :USART错误回调执行函数,输出错误代码
  100. **输入参数 :
  101. **输出参数 :
  102. ** 备注 :
  103. ********************************************************************************************************/
  104. void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
  105. {
  106. printf("Uart Error, ErrorCode = %d\r\n", huart->ErrorCode);
  107. }
  108. /********************************************************************************************************
  109. **函数信息 :void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
  110. **功能描述 :USART发送回调执行函数
  111. **输入参数 :
  112. **输出参数 :
  113. ** 备注 :
  114. ********************************************************************************************************/
  115. void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle)
  116. {
  117. if (HAL_UART_Receive_IT(UartHandle, (uint8_t *)aRxBuffer, 12) != HAL_OK)
  118. {
  119. Error_Handler();
  120. }
  121. }
  122. /********************************************************************************************************
  123. **函数信息 :void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  124. **功能描述 :USART接收回调执行函数
  125. **输入参数 :
  126. **输出参数 :
  127. ** 备注 :
  128. ********************************************************************************************************/
  129. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
  130. {
  131. /*通过中断方式接收数据*/
  132. if (HAL_UART_Transmit_IT(UartHandle, (uint8_t *)aRxBuffer, 12) != HAL_OK)
  133. {
  134. Error_Handler();
  135. }
  136. }
  137. #ifdef USE_FULL_ASSERT
  138. /**
  139. * @brief Reports the name of the source file and the source line number
  140. * where the assert_param error has occurred.
  141. * @param file: pointer to the source file name
  142. * @param line: assert_param error line source number
  143. * @retval None
  144. */
  145. void assert_failed(uint8_t *file, uint32_t line)
  146. {
  147. /* User can add his own implementation to report the file name and line number,
  148. tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  149. }
  150. #endif /* USE_FULL_ASSERT */

最终的代码中做了一些小修改,使程序可读性更强些:

  1. 初始化完成后,打印一条 Ready 消息
  2. 把初次发送的二进制数修改为 1,2,3 ... 9,0,回车,换行,共 12 个可打印字符
  3. 上位机的 XCOM 发送 10 个数字,选中“发送新行”,也就是加入回车和换行符,凑够 12 个字符

总结

  • 导入 DFP 的 pack 以后,使用 Keil MDK 可以正确配置 PY32F003x8
  • 空芯片的初次烧写会失败,但是后续烧写会成功。怀疑是不是初次烧写执行了类似 “Unlock Flash” 的操作,就像 J-Link 的 ARM-Flash 程序一样的功能?
  • 使用 1MHz 的 SWD 烧写速度,会出现小概率的烧写失败的情况,这时重新烧写一般都会成功。实验中没有出现反复多次烧写不成功的情况。后续再尝试降低一些 SWD 的速率看看
  • J-Link V8 不识别 PY 单片机,只能用 Cortex-M0+ 系列产品代替,代替后可以正常烧写
  • 本例中用到的 HAL 库函数和 STM32 系列的相同,GPIO_InitStruct 的定义和操作方法和 STM32 系列也完全相同
  • PY32F003x8 的 HAL_Receive_IT 函数和 HAL_Transmit_IT 函数的语法和作用,至少从功能上和 STM32 的相同。HAL_NVIC_xxx 函数接口和 STM32 也相同。也难怪,都是 Cortex-M0+ 的构架,代码通用也挺好的
  • PY32F003x8 的 UART 运行在 115200 波特率没问题。
  • 开发板上的 SWD RST 可以不接

初次尝试,可能对打算应用 PUYA 单片机的朋友有所借鉴,谬误之处,不吝指出。

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

闽ICP备14008679号