X
首页
技术
模拟电子
单片机
半导体
电源管理
嵌入式
传感器
最能打国产芯
应用
汽车电子
工业控制
家用电子
手机便携
安防电子
医疗电子
网络通信
测试测量
物联网
最能打国产芯
大学堂
首页
直播
专题
TI 培训
论坛
汽车电子
国产芯片
电机驱动控制
电源技术
单片机
模拟电子
PCB设计
电子竞赛
DIY/开源
嵌入式系统
医疗电子
颁奖专区
【厂商专区】
【电子技术】
【创意与实践】
【行业应用】
【休息一下】
最能打国产芯
活动中心
直播
发现活动
颁奖区
电子头条
参考设计
下载中心
分类资源
文集
排行榜
电路图
Datasheet
最能打国产芯
国产芯片交流
[MCU] CW32L010学习笔记
qzc0927
2024-11-15 17:32
楼主
CW32学习开发笔记
# 硬件原理图: ## 主芯片 ![image-20241114103849101](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114103849101.png) 引脚封装图: ![image-20241114104051352](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114104051352.png) CW32L010 是基于 eFlash 的单芯片低功耗微控制器,集成了主频高达 48MHz 的 ARM® Cortex®-M0+ 内核、 高速嵌入式存储器(多至 64K 字节 FLASH 和多至 4K 字节 SRAM)以及一系列全面的增强型外设和 I/O 口。 所有型号都提供全套的通信接口(二路 UART、一路 SPI 和一路 I2C)、12 位高速 ADC、四组通用和基本定时器、 一组低功耗定时器以及一组高级控制 PWM 定时器。 ## 供电电源 使用type-c直接供电即可,不需要再接其他电源转换芯片,CW32L010 可以在 -40℃到 85℃的温度范围内工作,供电电压宽达 1.62V ~ 5.5V。支持 Sleep 和 DeepSleep两种低功耗工作模式。 ![image-20241114104435067](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114104435067.png) ## 复位电路 ![image-20241114104524841](C:/Users/syz/AppData/Roaming/Typora/typora-user-images/image-20241114104524841.png) ## 滤波电路 ![image-20241114104852343](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114104852343.png) ## 内部稳压 ![image-20241114105052457](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114105052457.png) ![image-20241114105024829](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114105024829.png) ## 调试下载 默认使用SWD接口下载程序,原理图如下: ![image-20241114105146199](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114105146199.png) ## 板载指示灯 用于查看系统运行状态,原理图如下: ![image-20241114110648242](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114110648242.png) # 软件功能 ## 工程创建 具体如何创建工程就不所说明了,官方例程都有说明,我主要说下的我的目录结构设计: ![image-20241114105830013](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114105830013.png) ## 串口通讯 内部集成 2 个通用异步收发器 (UART),支持异步全双工、同步半双工和单线半双工模式,支持硬件数据流控 和多机通信,还支持 LIN(局域互连网络);可编程数据帧结构,可以通过小数波特率发生器提供宽范围的 波特率选择。内置定时器模块,支持等待超时检测、接收空闲检测、自动波特率检测和通用定时功能。 UART 控制器工作在双时钟域下,允许在深度休眠模式下进行数据的接收,接收完成中断可以唤醒 MCU 回到 运行模式。注意:仅 UART1 支持 LIN 和定时器功能;UART2 可通过片内外设互联与 BTIM/GTIM/ATIM 的从模式协同工 作实现超时定时器相关功能。我们接着实现串口通讯功能; - 1.串口功能硬件引脚 ![image-20241114135526600](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114135526600.png) 使用串口2来是实现通讯,再看引脚的复用功能。 ![image-20241114135659092](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114135659092.png) - 2.代码实现 ```C #include "bsp_uart2.h" #include "cw32l010_gpio.h" #include "cw32l010_uart.h" #include "stdio.h" #include "cw32l010_sysctrl.h" //UARTx #define DEBUG_UARTx CW_UART2 #define DEBUG_UART_CLK SYSCTRL_APB1_PERIPH_UART2 #define DEBUG_UART_APBClkENx SYSCTRL_APBPeriphClk_Enable1 #define DEBUG_UART_BaudRate 115200 #define DEBUG_UART_UclkFreq HSIOSC_VALUE //串口全速运行 //UARTx GPIO #define DEBUG_UART_GPIO_CLK (SYSCTRL_AHB_PERIPH_GPIOB) #define DEBUG_UART_TX_GPIO_PORT CW_GPIOB #define DEBUG_UART_TX_GPIO_PIN GPIO_PIN_5 #define DEBUG_UART_RX_GPIO_PORT CW_GPIOB #define DEBUG_UART_RX_GPIO_PIN GPIO_PIN_6 //GPIO AF #define DEBUG_UART_AFTX PB05_AFx_UART2TXD() #define DEBUG_UART_AFRX PB06_AFx_UART2RXD() static void UART_Configuration(void) { // //外设时钟使能,放在外设里面自己进行使能 DEBUG_UART_APBClkENx(DEBUG_UART_CLK, ENABLE); UART_InitTypeDef UART_InitStructure = {0}; UART_InitStructure.UART_BaudRate = DEBUG_UART_BaudRate; UART_InitStructure.UART_Over = UART_Over_16; UART_InitStructure.UART_Source = UART_Source_PCLK; UART_InitStructure.UART_UclkFreq = DEBUG_UART_UclkFreq; UART_InitStructure.UART_StartBit = UART_StartBit_FE; UART_InitStructure.UART_StopBits = UART_StopBits_1; UART_InitStructure.UART_Parity = UART_Parity_No ; UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None; UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx; UART_Init(DEBUG_UARTx, &UART_InitStructure); } /** *
@brief
配置GPIO * */ static void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; //外设时钟使能,放在外设里面自己进行使能 SYSCTRL_AHBPeriphClk_Enable(DEBUG_UART_GPIO_CLK, ENABLE); GPIO_WritePin(DEBUG_UART_TX_GPIO_PORT, DEBUG_UART_TX_GPIO_PIN,GPIO_Pin_SET); // 设置TXD的默认电平为高,空闲 GPIO_InitStructure.Pins = DEBUG_UART_TX_GPIO_PIN; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_Init(DEBUG_UART_TX_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.Pins = DEBUG_UART_RX_GPIO_PIN; GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP; GPIO_Init(DEBUG_UART_RX_GPIO_PORT, &GPIO_InitStructure); //UART TX RX 复用 DEBUG_UART_AFTX; DEBUG_UART_AFRX; } void UART2_Configuration(void) { UART_Configuration(); GPIO_Configuration(); } #ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */ /** * @brief Retargets the C library printf function to the UART. * */ PUTCHAR_PROTOTYPE { UART_SendData_8bit(DEBUG_UARTx, (uint8_t)ch); while (UART_GetFlagStatus(DEBUG_UARTx, UART_FLAG_TXE) == RESET); return ch; } size_t __write(int handle, const unsigned char * buffer, size_t size) { size_t nChars = 0; if (buffer == 0) { /* * This means that we should flush internal buffers. Since we * don't we just return. (Remember, "handle" == -1 means that all * handles should be flushed.) */ return 0; } for (/* Empty */; size != 0; --size) { UART_SendData_8bit(DEBUG_UARTx, *buffer++); while (UART_GetFlagStatus(DEBUG_UARTx, UART_FLAG_TXE) == RESET); ++nChars; } return nChars; } /****************************************************************************** * EOF (not truncated) ******************************************************************************/ #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ ``` - 3.编写打印测试函数 ```C static void Printf_Function(void) { DEBUG_LOG("\r\n"); DEBUG_LOG(" Compile time:"); DEBUG_LOG(__DATE__); DEBUG_LOG(" "); DEBUG_LOG(__TIME__); DEBUG_LOG("\r\n+-------------------+\r\n"); DEBUG_LOG("%s,%s,%d,%s\r\n", __FUNCTION__,__FILE__,__LINE__,__DATE__); DEBUG_LOG("\r\n+-------------------+\r\n"); } ``` - 4.查看串口终端信息 使用MobaXterm终端工具查看: ![image-20241114140550582](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114140550582.png) - 5.注意点 为了让代码支持GNU扩展,keil设置需要注意: ![image-20241114140950288](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114140950288.png) 同时,串口打印的时候,添加头文件`"stdio.h"`; ## GPIO口输入输出 根据板载资源,使用板载的LED来测试。前面硬件说明的时候提到,使用的引脚为PB00;就直接上代码了。 - 1.编写驱动代码 ```C #include "drv_led.h" // 初始化 LED 引脚 void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __SYSCTRL_GPIOB_CLK_ENABLE(); GPIO_InitStruct.IT = GPIO_IT_NONE; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pins = LED_GPIO_PINS; GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct); } // 控制 LED 开关 void LED_Control(GPIO_PinState state) { GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PINS,state); } // 切换 LED 状态 void LED_Toggle(void) { GPIO_TogglePin(LED_GPIO_PORT, LED_GPIO_PINS); } // 读取 LED 状态 int LED_Read(void) { return GPIO_ReadPin(LED_GPIO_PORT, LED_GPIO_PINS) == GPIO_Pin_SET ? 1 : 0; } // 定义并初始化 LED 操作结构体实例 LED_Ops_t myLED = { .init = LED_Init, .control = LED_Control, .toggle = LED_Toggle, .read = LED_Read }; ``` - 2.编写测试程序 ```C int32_t main(void) { bsp_init(); driver_init(); while(1) { SysTickDelay(1000); myLED.toggle(); } } ``` 调试下载之后,可直接观察板载LED灯是否在循环闪烁。 ## 调试等级 - 1.直接上代码,调试等级头文件; ```C #ifndef __LOG_H #define __LOG_H #include
#include
#include
#include
#define GLOB_LOG_EVEL LOG_DEBUG typedef enum { FALSE, TRUE } status; // 定义日志级别 typedef enum { LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR } LogLevel; //extern LogMsg lmsg; // 颜色 #define Blue "\033[34m" // Blue #define Green "\033[32m" // Green #define Yellow "\033[33m" // Yellow #define Red "\033[31m" // Red #define Reset "\033[0m" // Reset color // 记录日志的宏定义 #define LOG_MESSAGE(format, ...) printf("[NTP]:%s(),Line:%05d: " format "\r\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) void LOG_MSG(LogLevel level, const char *message); #endif ``` - 2.功能函数实现文件: ```C #include "log.h" // 日志输出函数 void LOG_MSG(LogLevel level, const char *message) { switch (level) { case LOG_DEBUG: printf(Blue "DEBUG: %s" Reset "\r\n", message); break; case LOG_INFO: printf(Green "INFO: %s" Reset "\r\n", message); break; case LOG_WARNING: printf(Yellow "WARNING: %s" Reset "\r\n", message); break; case LOG_ERROR: printf(Red "ERROR: %s" Reset "\r\n", message); break; default: printf("UNKNOWN: %s\n", message); break; } } ``` - 3.编写测试函数 ```C /*宏定义错误码信息*/ static void Error_Code_Info(void) { DEBUG_LOG("%d", SYSTEM_OK); DEBUG_LOG("%d", SYSTEM_ERR_E_1); DEBUG_LOG("%d", SYSTEM_ERR_E_2); DEBUG_LOG("%d", SYSTEM_ERR_MQTT_INFO_ERROR); LOG_MSG(LOG_DEBUG, "This is a debug message"); LOG_MSG(LOG_INFO, "This is an info message"); LOG_MSG(LOG_WARNING, "This is a warning message"); LOG_MSG(LOG_ERROR, "This is an error message"); } ``` - 4.终端输出 ![image-20241114145804066](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114145804066.png) ## 串口中断 CW32单片机的串口有好几种工作方式,异步全双工,同步半双工,单线半双工,由于没有DMA通道,为了避免频繁的进入中断,采用串口接收中断,串口查询发送方式实现收发; 配置简单队列消息,实现方式如下: - 1、定义队列结构 ```C #define myQ2_SIZE 512 #define RxBuffer2_SIZE myQ2_SIZE typedef volatile struct { uint8_t m_getIdx; uint8_t m_putIdx; uint8_t m_entry[ myQ2_SIZE ]; } myQ2; extern myQ2 volatile RxBuffer2; extern myQ2 volatile TxBuffer2; void UART2_Buffer_Init(void); ``` - 2、初始化队列结构 ```C myQ2 volatile RxBuffer2; myQ2 volatile TxBuffer2; void UART2_Buffer_Init(void) { CBUF_Init(RxBuffer2); CBUF_Init(TxBuffer2); } ``` - 3、使能串口接收中断 ```C void NVIC_Configuration(void) { //优先级,无优先级分组 NVIC_SetPriority(DEBUG_UART_IRQ, 0); //UARTx中断使能 NVIC_EnableIRQ(DEBUG_UART_IRQ); //使能UARTx RC中断 UART_ITConfig(DEBUG_UARTx, UART_IT_RC, ENABLE); UART_ClearITPendingBit(CW_UART2, UART_IT_RC); } ``` - 4、编写测试函数,实现串口功能收发 ```C int32_t main(void) { bsp_init(); driver_init(); while(1) { uint16_t dataLen=0; dataLen = CBUF_Len(RxBuffer2); if(dataLen!=0) { //拷贝数据 memcpy((char*)TxBuffer2.m_entry,(char*)RxBuffer2.m_entry,dataLen); //查询发送数据 UART_SendBuf_Polling(CW_UART2,TxBuffer2.m_entry,dataLen); USART2_Clear(); } SysTickDelay(1000); myLED.toggle(); } } ``` - 5、查看串口终端收发 ![image-20241115144847070](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241115144847070.png) 从截图可以看出,当前收发数据一致; ## 控制台Shell 下面介绍下开源项目是 letter-shell,一个功能强大的嵌入式shell,letter shell 3.x是一个C语言编写的,可以嵌入在程序中的嵌入式shell,通俗一点说就是一个串口命令行,可以通过命令行调用、运行程序中的函数。目前 letter-shell 3.0版本支持的功能有: - 命令自动补全 - 快捷键功能定义 - 命令权限管理 - 用户管理 - 变量支持 > 项目地址:https://github.com/NevermindZZT/letter-shell 移植过程: - 1.复制源码到工程中: ![image-20241115165344228](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241115165344228.png) - 2.在自定义接口`shell_port.c`中实现自己的串口读写函数 ```C #include "shell.h" #include "main.h" #include "bsp_uart2.h" #include "shell_port.h" Shell shell; char shellBuffer[512]; /** * @brief 用户shell写 * * @param data 数据 * @param len 数据长度 * *
@return
short 实际写入的数据长度 */ short userShellWrite(char *data, unsigned short len) { UART_SendBuf_Polling(CW_UART2,(uint8_t *)data, len); return len; } /** * @brief 用户shell读 * * @param data 数据 * @param len 数据长度 * * @return short 实际读取到 */ short userShellRead(char *data, unsigned short len) { return UART2_GetString((uint8_t *)data, len); } /** * @brief 用户shell上锁 * * @param shell shell * * @return int 0 */ int userShellLock(Shell *shell) { return 0; } /** * @brief 用户shell解锁 * * @param shell shell * * @return int 0 */ int userShellUnlock(Shell *shell) { return 0; } /** * @brief 用户shell初始化 * */ void userShellInit(void) { //注册自己实现的写函数 shell.write = userShellWrite; // shell.read = userShellRead; //调用shell初始化函数 shellInit(&shell, shellBuffer, 512); } ``` - 3.在终端函数中定义 对于裸机环境,在主循环中调用`shellTask`,或者在接收到数据时,调用`shellHandler`,我这里在中断中调用 ```C void UART2_IRQHandler(void) { /* USER CODE BEGIN */ uint8_t TxRxBuffer; if (UART_GetITStatus(CW_UART2, UART_IT_RC) != RESET) { /*使用简易队列进行接收数据*/ TxRxBuffer = UART_ReceiveData_8bit(CW_UART2); shellHandler(&shell,TxRxBuffer); CBUF_Push(RxBuffer2, TxRxBuffer); UART_ClearITPendingBit(CW_UART2, UART_IT_RC); } /* USER CODE END */ } ``` - 4.调用初始化shell ```C userShellInit(); ``` - 5.串口终端实现结果 ![image-20241115170003058](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241115170003058.png) 查看当前系统时钟: ![image-20241115170036353](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241115170036353.png) 其他实现方式,参考官方文档说明。
点赞
回复评论 (2)
沙发
lemonboard
QFN20 是不是太小巧可爱了啊
点赞
2024-11-15 23:49
板凳
Jacktang
用type-c直接供电比较方便了
点赞
2024-11-16 09:18
最新活动
是德科技有奖直播 | 应对未来高速算力芯片的设计与测试挑战
免费申请 | 上百份MPS MIE模块,免费试用还有礼!
TI 有奖直播 | 使用基于 Arm 的 AM6xA 处理器设计智能化楼宇
Follow me第二季第3期来啦!与得捷一起解锁高性能开发板【EK-RA6M5】超能力!
报名直播赢【双肩包、京东卡、水杯】| 高可靠性IGBT的新选择——安世半导体650V IGBT
30套RV1106 Linux开发板(带摄像头),邀您动手挑战边缘AI~
随便看看
交流贴-面向状态的嵌入式开发框架
ISP检测不到硬件(s51)是怎么绘事??急,谢谢 在线等
急急急急急急急急急急急!!!!!!最近在接触英特尔手册中的APIC,谁能告诉我触发模式是什么???高手请进
请教大家,将wince6.0升级到r3之后,explorer无法启动,进者有分
wince如何连接网络打印机?
近期IC创业三大怪(转)
如何降低UCD30xx 系列数字电源控制器DPWM抖动
我们需要在工作中找出自己的亮点
请教关于高精度AD变换
MSP430F5438A-EP和MSP430F5132IDA型号中各字母代表的含义
电子设计竞赛赛题的出题的过程和思路
手机SIM卡编号的含义
KeilMDK+Ulink2如何支持Flash大于128K的STM32芯片
C语言编程艺术--条件编译(zt)
免费申请TI 样片,晒单赢好礼!
EEWORLD大学堂----斩波电路(2) - 降压斩波电路仿真
【电机分类】-转载
2013年全国大学生电子设计竞赛(陕西赛区TI杯)获奖公示名单
如何让开发的驱动程序和应用程序一一对应呢
求助
电子工程世界版权所有
京B2-20211791
京ICP备10001474号-1
京公网安备 11010802033920号
回复
写回复
收藏
回复