MM32F0270
对于控制步进电机来说,最重要的控制参数是脉冲的数量和频率,两者结合可以实现满足要求的电机加减速曲线。在一些电机应用数量不多的场合,通常使用定时器中断发送脉冲来控制步进电机,优点是原理简单代码易于实现。但是一旦控制的电机多起来,就会占用大量的MCU资源,这在大多数情况下是不可接受的,更不用说多轴联动了。那么如何做到占用很少的MCU资源,又能实现脉冲发送的精确控制?
于是就想到了使用DMA功能更新PWM的输出, DMA全称Direct Memory Access,即直接存储器访问。DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。它允许不同速度的硬件装置来沟通,而不需要依赖于MPU的大量中断负载。
通过设置DMA传输数据的数量,可以控制发送的脉冲数。通过设置不同的装载值和顺序,可以使用不同频率和脉宽。当需要发送较多数量的脉冲时,则可以使用DMA传输完成中断中切换DMA传输的数据起始地址及发送数量,继续发送。这个方法即方便,又减轻MPU的负担,可以同时驱动多个电机工作,还可以根据电机的启动、运行、停止使用不同的频率。
定时器DMA模式
MM32F0270的定时器TIM1、TIM2、TIM3、TIM15、TIM16/17有DMA模式,能够在发生单个事件时生成多个DMA 请求。主要目的是在没有软件开销的情况下,多次重新编程定时器的一部分,也可以用于按周期读取数个寄存器。下面以TIM1为例介绍:
TIM1_DCR 和 TIM1_DMAR 寄存器跟 DMA 模式相关。DMA 控制器的目标是唯一的,必须指向TIM1_DMAR 寄存器。开启 DMA 使能后,在给定的 TIM1 事件发生时, TIM1 会给 DMA 发送请求。
对 TIM1_DMAR 寄存器的每次写操作都被重定向到一个 TIM1 寄存器。TIM1_DCR寄存器的DBL位定义了DMA连续传送的长度,即传输寄存器数量;当对TIM1_DMAR进行读写操作时,定时器识别 DBL,确定传输的寄存器数量。TIM1_DCR 寄存器的 DBA 位定义了DMA 传输的基地址, 定义从 TIM1_CR1 寄存器地址开始的偏移量(00000 为 TIM1_CR1;00001 为TIM1_CR2;……; 00110 为 TIM1_CCMR1 等)。
通过定时器的DMA模式来更新PWM,本文参官网例程“TIM1_DMA_UPData”进行说明具体实现方法。
实验
本实验使用TIM1的DMA模式,当更新事件发生时,更新 TIM1_CCR1、TIM1_CCR2 和 TIM1_CCR3 寄存器的内容。程序中配置TIM1的通道1、通道2、通道3输出PWM,再通过DMA搬运数据来改变PWM的占空比。定时器每产生一个溢出事件(即计数完成),就发送DMA请求,根据数据在数组中的排列顺序以生成所需要的时序。
程序部分
GPIO初始化
配置TIM1_CH1、TIM1_CH2 和 TIM1_CH3对应的GPIO。
void TIM1_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE); GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_2); GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_2); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_2); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); }
TIM1 DMA初始化
TIM1_CH3对应DMA1通道5,将data[]中的数据传送到TIM1_DMAR寄存器,传输方向从存储器到外设,数据宽度为半字,使能DMA传输完成中断。
void TIM_DMA_Init(void) { DMA_InitTypeDef DMA_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1, ENABLE); DMA_DeInit(DMA1_Channel5); DMA_StructInit(&DMA_InitStruct); //Transfer register address DMA_InitStruct.DMA_PeripheralBaseAddr = (u32) & (TIM1->DMAR); //Transfer memory address DMA_InitStruct.DMA_MemoryBaseAddr = (u32)data; //Transfer direction, from memory to register DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStruct.DMA_BufferSize = 6; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Transfer completed memory address increment DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; DMA_InitStruct.DMA_Auto_reload = DMA_Auto_Reload_Disable; DMA_Init(DMA1_Channel5, &DMA_InitStruct); DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE); }
TIM1 PWM初始化
TIM1输出PWM,配置时钟分频系数和预装载值,递增计数,使用PWM模式1,输出高电平有效,分别对TIM1_CH1、TIM1_CH2、TIM1_CH3指定要加载到捕获比较寄存器中的脉冲值为arr/2、arr/4、arr/6,使能TIM1的DMA模式,起始地址为TIM1_CCR1,传输长度为3。
void TIM1_PWM_Init(u16 arr, u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; TIM_OCInitTypeDef TIM_OCInitStruct; RCC_APB2PeriphClockCmd(RCC_APB2ENR_TIM1, ENABLE); TIM_TimeBaseStructInit(&TIM_TimeBaseStruct); TIM_TimeBaseStruct.TIM_Period = arr; TIM_TimeBaseStruct.TIM_Prescaler = psc; //Setting Clock Segmentation TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStruct.TIM_RepetitionCounter = 0; ///TIM Upward Counting Mode TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct); TIM_OCStructInit(&TIM_OCInitStruct); //Select Timer Mode: TIM Pulse Width Modulation Mode 2 TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //Setting the Pulse Value of the Capture Comparison Register to be Loaded TIM_OCInitStruct.TIM_Pulse = arr / 2; TIM_OC1Init(TIM1, &TIM_OCInitStruct); TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_OCInitStruct.TIM_Pulse = arr / 4; TIM_OC2Init(TIM1, &TIM_OCInitStruct); TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_OCInitStruct.TIM_Pulse = arr / 6; TIM_OC3Init(TIM1, &TIM_OCInitStruct); TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM1, ENABLE); TIM_DMAConfig(TIM1, TIM_DMABase_CCR1, TIM_DMABurstLength_3Bytes); TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE); TIM_Cmd(TIM1, ENABLE); }
使能DMA1通道5
DMA_Cmd(DMA1_Channel5, ENABLE);
配置NVIC
NVIC_Configure(DMA1_Channel4_5_6_7_IRQn, 1, 1);
DMA1中断服务子程序
void DMA1_Channel4_5_6_7_IRQHandler() { if (DMA_GetITStatus(DMA1_IT_TC5)) { //clear IRQ flag DMA_ClearITPendingBit(DMA1_IT_TC5); } }
定义数组data[]
static u16 data[] = {2000, 3000, 4000, 8000, 7000, 6000};
Main()函数
s32 main(void) { TIM1_GPIO_Init(); TIM1_PWM_Init(10000, 0); TIM_DMA_Init(); NVIC_Configure(DMA1_Channel4_5_6_7_IRQn, 1, 1); DMA_Cmd(DMA1_Channel5, ENABLE); while (1) { } }
演示
下载程序到目标板。连接逻辑分析仪测试PA8、PA9、PA10的输出,打开对应上位机软件启动采样,运行程序,各通道的PWM输出情况如下:
![“使用MM32F0270](http://mcu.eetrend.com/files/2022-02/wen_zhang_/100557585-242233-1.png)
截取其中1个周期观察:
![“使用MM32F0270](http://mcu.eetrend.com/files/2022-02/wen_zhang_/100557585-242234-2.png)
TIM1_CH1输出PWM占空比为20%和80%, TIM1_CH1输出PWM占空比为30%和70%, TIM1_CH1输出PWM占空比为40%和60%,运行结果和预期一致。
实验简单演示了MM32F0270的定时器TIM1的DMA方式更新PWM,通过该方案可以实现多路、不同频率、不同脉宽、数量精确可控的PWM波。
参考Demo程序可登录MindMotion的官网下载MM32F0270库函数和例程 :
https://www.mindmotion.com.cn/products/mm32mcu/mm32f/mm32f_mainstream/mm32f0270/
工程路径如下:
~ MM32FMM32F0270_Lib_Samples\MM32F0270_Samples\LibSamples\TIM\TIM1_DMA_UPData。
来源:灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。
![](https://cdn.eetrend.com/files/styles/solid-pic-400x250/public/2022-02/wen_zhang_/100557585-242233-1.png?itok=uLWzoUYK)
![](https://cdn.eetrend.com/files/styles/solid-pic-400x250/public/2022-02/wen_zhang_/100557585-242234-2.png?itok=4fAI_yrA)
在许多的PC的USB应用中,越来越多的需要使用低功耗功能,PC可结合USB提供一定的供电能力,使得外设在1.5W以内,可以不用其他单独的外部供电;更巧妙的是PC可以进入Sleep,驱使USB外设也进入Suspend状态,达到只提供2.5mA的供电需求,以达到低功耗的目的。灵动微电子推出的MM32F0270系列,支持多种灵活的低功耗模式,支持Suspend模式的USB Device模块。USB外设支持 USB挂起 /恢复操作,可以通过停止MCU时钟来实现降低功耗。
当USB设备处于挂起状态时,它仍然为其D+或D-及上拉电阻器供电,以保持空闲状态并保持其内部状态,包括地址和配置。当它被USB总线上的恢复信号唤醒时,它不需要经历重新枚举过程。
USB总线上的恢复信号可以由主机和设备发送。远程唤醒功能使USB设备能够唤醒挂起的主机;例如,将鼠标连接到笔记本电脑时,您可以通过单击鼠标来唤醒已经进入睡眠状态的笔记本电脑(PC端需要配置为支持远程唤醒)。远程唤醒功能在枚举阶段在配置描述符中报告,并且可以使用标准 USB 请求启用(或禁用)。
本文介绍了如何使用 MM32F0270的USB来实现通过接收USB的D+/D-信号在实现Suspend/Resume的状态转换。
1、MM32F0270 USB的简要介绍
符合 USB 2.0全速设备的技术规范;
- 支持全速模式(12M)
- 包含四个独立的通用端点和一个控制传输端点用于中断传输和批量传输
- 控制、批量 、 中断传输 最大可传输 64字节的包
- CRC生成 /校验, NRZI编码 /解码和位填充
- 支持 USB挂起 /恢复操作
- 支持 DMA传输
![“图1](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100557221-240622-1.png)
2、USB的功能特性
2.1、MM32的USB具有以下特性
USB模块可以为PC主机和微控制器提供一种符合USB规范的通信连接,用于两者所实现的功能之间的连接。PC主机和微控制器之间通过数据缓冲区完成数据传输,USB模块与PC主机通信,根据USB规范完成对令牌分组的检测,对数据发送/接收和握手分组的处理。由硬件完成对包括CRC的生成和校验等整个传输的格式。每一个端点都有一个64字节缓冲区描述块,且该缓冲区是在USB模块内部,不能直接被CPU访问的。一个有效的功能/端点的令牌分组被USB模块识别,当端点已配置完成后发生相关的数据传输。USB模块与专用数据缓冲区的数据交换通过内部寄存器完成。在所有的数据传输完成后,根据需要的传输方向,发送或接收适当的握手分组。
数据传输完成时,USB模块会触发端点相关的中断,通过读取状态寄存器或利用不同的中断处理程序,可以确定:
- 主机请求的传输类型
- 哪个端点需要得到服务
- 正在进行的是哪种类型的服务
- 端点的应答
- 传输是否完成
USB模块在不工作时,可以通过配置USB_POWER寄存器使 USB模块处于SUSPEND模式(低功耗模式)。USB模块在低功耗模式下,USB时钟会减慢或停止且USB模块不产生静态电流功耗。USB模块在低功耗模式下,可以通过USB线上数据传输将其唤醒,也可以通过软件直接将其唤醒。或者通过将特定的中断输入源连接到唤醒引脚上,使系统立即恢复正常的时钟,可以直接启动或停止时钟系统。
2.2、MM32F0270 USB用于挂起和恢复的USB总线状态
USB 规范定义了与 USB 总线上的信号电压相对应的总线状态。
下图为连接到D+的1.5 kΩ上拉电阻的全速总线。
![“使用MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100557221-240623-2.jpg)
MM32F0270系列芯片内置1.5K上拉电阻。
下面介绍USB 总线如何定义挂起、恢复和空闲状态的总线状态。
设备的挂起
在USB系统中,正常状态下PC,Hub或Root Hub会一直周期性地发送SOF包(Start Of Frame,全速USB每1ms发送一个,高速USB则是125µs发送一个)。根据USB协议,如果USB线上一直处于空闲(Idle)状态超过3ms,设备应该把它当作一个挂起(Suspended)信号,要求设备在10ms内进入挂起状态,并把设备所需的电流大小降到规定的值;对于low-power设备,要求是500µA,而对于high-power或支持远程唤醒(remote wakeup)功能的设备是2.5mA。在挂起状态中,设备必须继续向数据项D+/D-的上拉电阻提供电压以维持Idle状态。
![“使用MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100557221-240624-3.jpg)
设备的唤醒
设备处于挂起状态时,任何总线上的活动(非空闲信号)都可以把设备唤醒/恢复,从而退出低功耗模式。同样,设备也可以换醒host,比如电脑待机时通过USB键盘来换醒主机,这种功能称之为“远程唤醒”(remote wakeup),不在本文的讨论范围内。
因为设备挂起时处于全速信号,在当host需要把将设备退出suspend状态时,需要先发送一个持续时间超过20ms的Fulll Speed K状态。设备看到K状态结束的1.3us内醒过来,而host需要在3ms内发送SOF信号以维持正常的高速信号模式,否则设备又将进入suspend。如下图所示:
![“使用MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100557221-240625-4.jpg)
下面是USB的数据状态与信号的说明:
▶▶数据 J 和 K 状态Data J and K states
对于全速总线段,J 状态与差分 1 相同,即 D+ 为逻辑高电平时和 D- 为逻辑低电平,而 K 状态与差分 0 相同,即当 D+ 为逻辑低电平且D- 是逻辑高电平。
▶▶空闲状态Idle state
在空闲状态下,对于全速总线段,D+ 比 D- 的电平高。
▶▶挂起状态Suspend signal
由于当USB总线处于空闲状态超过3 ms时进入挂起状态,因此挂起状态与空闲状态相同或与全速总线段中的J状态相同。
▶▶恢复信号Resume signal
当设备处于挂起状态时,设备端口上的数据K状态表示从挂起状态恢复。这意味着恢复信号是全速段中从数据J状态到数据K状态的变化。
2.3、MM32F0270 USB支持从Suspend模式下唤醒
MM32F0270 可通过EXTI线 18连接到 USB总线挂起中断实现USB从挂起状态唤醒。
需要使用唤醒时,需要使能相应的USB中断外,还需配置EXTI 18以使能相关的功能。
相关的寄存器与控制状态位的控制与查询,可以参考MM32F0270的用户手册。
3、USB进入Suspend与Res ume的软硬件设计
3.1、在库函数版本的样例中可以通过如下顺序初始化USB
a.配置系统时钟为48MHz或96Mhz,使能GPIOA时钟,使能USB时钟
void USB_ClockConfig(void) { USB_HSI48M_Config(); Set_CRS(); // The calibration of vibration // Select USBCLK source // RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div2); //if SYSCLK is 96MHz // Enable USB clock RCC_APB1PeriphClockCmd(RCC_APB1ENR_USB, ENABLE); }
b.配置USB D+和D-所需用到的GPIO引脚,使用GPIO_Configuration函数
void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStruct; GPIO_StructInit(&GPIO_InitStruct); RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE); // USB_DISCONNECT used as USB pull-up GPIO_InitStruct.GPIO_Pin = USB_DISCONNECT_PIN; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_FLOATING; GPIO_Init(USB_DISCONNECT, &GPIO_InitStruct); }
c.配置USB的中断,调用USB_NVIC_Config函数
void USB_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = USB_IRQn; NVIC_InitStruct.NVIC_IRQChannelPriority = 0; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); }
d.设置USB的时钟,调用USB_ClockConfig
void USB_ClockConfig(void) { USB_HSI48M_Config(); Set_CRS(); // The calibration of vibration // Select USBCLK source // RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div2); // Enable USB clock RCC_APB1PeriphClockCmd(RCC_APB1ENR_USB, ENABLE); }
e.设置USB 初始化
void USB_Init(void) { pInformation = &Device_Info; pInformation->ControlState = 2; pProperty = &Device_Property; pUser_Standard_Requests = &User_Standard_Requests; // Initialize devices one by one pProperty->Init(); }
f.设定USB对应唤醒的EXTI参数
void USB1_WKUP_Init(void) { EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line18; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); }
g.中断相应处理函数
void USB_Istr(void) { __IO u16 wIstr; wIstr = _GetUSB_INT_STA(); //USB->INT_STATE = wIstr; // fSuspendEnabled = 0; if(wIstr & USB_INT_STATE_RSTF) { _ClrUSB_INT_STA(USB_INT_STATE_RSTF) ; Device_Property.Reset(); } //… EXTI_ClearITPendingBit(EXTI_Line22); }
3.2、实现main Demo功能的主要函数代码
s32 main(void) { GPIO_Configuration(); USB_NVIC_Config(); USB_ClockConfig(); USB_Init(); while(1) { if(bDeviceState == CONFIGURED) { if(!(_GetUSB_CTRL1()&EP1_CTRL_TRANEN)) { UserToPMABufferCopy(gTableData, ENDP1, BUFF_SIZE); _SetUSB_CTRL1(EP1_CTRL_TRANEN | BUFF_SIZE) ; //Loop IN transmission } } } }
配置好初始化USB收发的初始化操作后,PC端会发现USB HID枚举成功;此时PC端进入待机模式,
![“使用MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100557221-240626-5.png)
MCU的USB收到Suspend的命令后,执行:
void Suspend(void) { if(bDeviceState == CONFIGURED) { //Frequency the bus clock 512 USB->POWER &= ~USB_POWER_SUSP; bDeviceState = SUSPENDED; fSuspendEnabled = true; RCC->CFGR &= ~RCC_CFGR_HPRE; RCC->CFGR |= RCC_CFGR_HPRE_DIV512; RCC->CR &= ~(0x1f << 26); RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div4); UART_DeInit(UART1); } }
▶▶USB唤醒机制
USB设备进入挂起状态之后,将由Resume信号进行唤醒。Resume信号可以由USB主机发起,也可以由USB设备本身触发,但是只有USB主机可以结束Resume信号。
主机在挂起设备后可通过翻转数据线上的极性并保持20ms来唤醒设备,并以低速EOP信号结尾。
如果设备支持远程唤醒,设备可向主机发起远程唤醒请求,前提是设备已进入idle状态至少5ms,设备会驱动总线进入K状态,如下图,K状态必须维持1ms-15ms之内,此信号会在1ms内被主机接管,主机会继续驱动唤醒信号直到20ms,并以低速EOP信号结尾。
主机复位设备或者设备对自己强行复位,设备也会从挂起状态切换到默认状态。
MM32F0270 设备被唤醒后,如果唤醒中断使能(比如使用PA0的EXTI0),则会进入唤醒中断,退出低功耗模式,然后清除USB_POWER寄存器的SUSPEND位,退出强制挂起操作。
操作上体现为PC Host主机同按主机KeyBoard或鼠标按键实现退出睡眠状态,从而唤醒MM32F0270的挂起状态。
通过上述的步骤,简单的演示了MM32F0270的USB 接收数据,通过数据帧中的Start Bit唤醒MCU的功能。
Demo程序可登录MindMotion的官网下载MM32F0270 lib_Samples
https://www.mindmotion.com.cn/products/mm32mcu/mm32f/mm32f_mainstream/MM32F0270/
工程路径如下:
~ MM32F0270_Samples\LibSamples\USB\
来源:灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100557221-240622-1.png?itok=r_kDuqiK)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100557221-240623-2.jpg?itok=eKp_Kg1j)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100557221-240624-3.jpg?itok=VZFuCZTx)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100557221-240625-4.jpg?itok=QLvtkg9W)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100557221-240626-5.png?itok=HTbSGUNF)
在许多的工业与消费类应用中,越来越多的需要使用低功耗功能,使用外部串口数据通信发送命令来唤醒MCU。灵动微电子推出的MM32F0270系列,支持多种灵活的低功耗模式,支持LPUART的外设。
本文介绍了如何使用 MM32F0270的LPUART来实现通过接收外部UART的信号,触发MCU从Sleep/DeepSleep低功耗模式中唤醒。
1、MM32F0270 LPUART的简要介绍
LPUART 为低功耗通用异步收发器,相比标准的UART,其功耗极低,并支持在Sleep,DeepSleep模式运行以及唤醒芯片。
LPUART 工作时钟为32768Hz。通过配置LPUART 数据收发的最高支持波特率为9600。MM32F0270的LPUART 的时钟源仅支持LSE 32.768KHz,结合LSE的特性,LPUART 能够在所有电源模式(待机模式除外)下保持运行状态。
LPUART 可以支持MCU结合LPUART的接收特性,触发MCU从低功耗SLEEP/DeepSleep模式唤醒,实现非通信时的低功耗运行。
![“图1](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100556998-239543-1.png)
2、LPUART 的功能特性
2.1 MM32的LPUART具有以下特性:
- 支持UART 帧格式的异步数据收发
- 支持DMA 请求(RUN 或LPRUN 模式下支持DMA,Sleep/DeepSleep 模式下不支持DMA)
- 全双工异步操作
- 工作时钟为32768Hz LSE 时钟或40KHz LSI 时钟,经过分频后波特率范围为300~9600
- 内置独立的1 字节发送和1 字节接收缓冲
- 发送和接收数据低位在前
- 一个起始位开始,后面接数据位,输出的数据长度可为7 位、8 位,最后为停止位。另外可选择是否有加奇偶校验位,奇偶校验位在数据位之后停止位之前。
- 支持硬件奇数或者偶数校验产生和侦测
- 支持信号接收和发送取反
- 支持Sleep/DeepSleep 模式进行数据收发
2.2 MM32F0270 LPUART中断
LPUART支持下面中断源:
- 接收缓冲溢出
- 帧错误
- 奇偶校验错误
- 接收器检测到起始位
- 接收器检测到下降沿
- 接收器完整接收 1byte数据
- 接收器完整接收数据且与预设数据匹配
- 发送器数据完成发送
- 发送器缓冲空
2.3 MM32F0270 LPUART支持唤醒源
LPUART支持 Sleep/DeepSleep模式以下唤醒源:
- 接收器检测到下降沿唤醒
- 接收器检测到起始位唤醒
- 接收器 1字节接收完成唤醒
- 接收器 1字节数据接收并匹配唤醒
需要使用唤醒时,需要使能相应的中断外,还需配置EXTI 22使能相关的功能。
相关的寄存器与控制状态位的控制与查询,可以参考用户手册。
3、 LPUART 从Sleep/DeepSleep模式唤醒的软硬件设计
LPUART是如何控制配置实现接收UART数据,利用对方UART发送一个Byte中的START起始位,唤醒Sleep/DeepSleep模式的呢?
3.1在库函数版本的样例中可以通过如下顺序初始化LPUART
a. 使能SYSCFG ,PWR,BKP,LSE时钟,待LSE稳定,使能LPUART时钟;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_SYSCFG, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1ENR_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); RCC_LSEConfig(RCC_LSE_ON); DelayNop_Init(); DelayNop_Ms(100); while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) {;} RCC_APB2PeriphClockCmd(RCC_APB2ENR_LPUART1, ENABLE);
b. 配置LPUART的LPUART_InitTypeDef结构体中指定的参数;
选择时钟源为LSE 32.768KHz;
选择波特率为9600Bps,8个数据位,1个停止位,无校验位;
对应9600Bps的MDU匹配值为0x952;
LPUART_InitTypeDef init_struct; LPUART_StructInit(&init_struct); init_struct.LPUART_Clock_Source = 0; init_struct.LPUART_BaudRate = LPUART_Baudrate_9600; init_struct.LPUART_WordLength = LPUART_WordLength_8b; init_struct.LPUART_StopBits = LPUART_StopBits_1; init_struct.LPUART_Parity = LPUART_Parity_No; init_struct.LPUART_MDU_Value = 0x952; init_struct.LPUART_RecvEventCfg = LPUART_RecvEvent_Start_Bit; LPUART_Init(LPUART1, &init_struct);
c. 使能LPUART接收中断
LPUART_ClearITPendingBit( LPUART1, LPUART_LPUIF_RXIF); LPUART_ITConfig( LPUART1, LPUART_LPUCON_RXIE, ENABLE );
d. 设置LPUART中断向量
void NVIC_LPUART_ConfigInit(void) { NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = LPUART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPriority = 1; NVIC_Init( &NVIC_InitStruct); }
e. 设置LPUART1复用的GPIO,复用到PA4&PA5;
void LPUART1_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE); GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_3); GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_3); //LPUART1_TX GPIOA.4 GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStruct); //LPUART1_RX GPIOA.5 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStruct); }
f. 设定LPUART对应唤醒的EXTI参数
void LPUART1_WKUP_Init(void) { EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line22; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); }
g. 中断相应处理函数
void LPUART1_IRQHandler() { if(LPUART_GetFlagStatus(LPUART1, LPUART_LPUSTA_START)==SET) { LPUART_ClearFlagStatus(LPUART1,LPUART_LPUSTA_START); rxDataBuf[cnt++] = LPUART_ReceiveData(LPUART1); if(cnt >= 10) cnt_flag = 1; } EXTI_ClearITPendingBit(EXTI_Line22); }
3.2 实现Demo功能的主要函数代码:
void LPUART_Function_Demo(void) { u8 temp, i; u8 string1[] = "enter low power mode\n"; u8 string2[] = "wakeup from low power mode\n"; LPUART_Interrupt_wStart_Init(); LPUART_ClearITPendingBit( LPUART1, LPUART_LPUIF_RXIF); LPUART_ITConfig( LPUART1, LPUART_LPUCON_RXIE, ENABLE ); NVIC_LPUART_ConfigInit(); LPUART_Cmd(LPUART1, ENABLE); LPUartSendGroup(&(string1[0]),sizeof(string1)); LPUART1_WKUP_Init(); __WFI(); LPUartSendGroup(&(string2[0]),sizeof(string2)); while(1) { temp = Input_Byte(LPUART1); if(temp != 0) { Output_Byte(LPUART1, temp); } } }
配置好初始化LPUART收发的初始化操作后,发送“enter low power mode”;
进入Sleep/DeepSleep模式。
PC Side发送任意数据,LPUART收到PC side的数据后,MCU从Sleep/DeepSleep模式唤醒。
唤醒后继续执行LPUART发送程序,发送“wakeup from low power mode”到PC主机。
![“使用MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100556998-239544-2.png)
通过上述的步骤,简单的演示了MM32F0270的LPUART 接收数据,通过数据帧中的Start Bit唤醒MCU的功能。
Demo程序可登录MindMotion的官网下载MM32F0270 lib_Samples:
https://www.mindmotion.com.cn/products/mm32mcu/mm32f/mm32f_mainstream/MM32F0270/
工程路径如下:
~ MM32F0270_Samples\LibSamples\LPUART\
来源:灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。
![](https://cdn.eetrend.com/files/styles/solid-pic-400x250/public/2022-01/wen_zhang_/100556998-239543-1.png?itok=rN8sPSy_)
![](https://cdn.eetrend.com/files/styles/solid-pic-400x250/public/2022-01/wen_zhang_/100556998-239544-2.png?itok=n6MA7veQ)
UART空闲中断
在实际项目中经常用到串口接收一些不定长的数据,此时必须面对一个问题:怎么判断这一帧数据接收完成了呢?通常使用UART非空中断配合简单的数据协议,在数据中加入帧头、帧尾,在程序中判断是否接收到帧尾来确定数据接收完毕,因为对每个数据都要进行判断,比较消耗系统资源,尤其是在一些实时性要求较高的场合。而串口空闲中断可以大大简化数据接收过程的判断,在这一块起到非常重要的作用。
空闲中断(IDLE),俗称帧中断,即第一帧数据接收完毕到第二帧数据开始接收期间存在一个空闲状态(每接收一帧数据后空闲标志位置1),检测到此空闲状态后即执行中断程序。空闲中断的优点在于省去了帧头帧尾的检测,进入中断程序即意味着已经接收到一组完整数据,仅需即时对数据处理或将数据转移出缓冲区即可。
串口空闲中断在串口无数据接收的情况下,是不会产生的,产生的条件是当清除空闲标志位后,必须有接收到第一个数据后,才开始触发,一旦接收的数据断流,没有接收到数据,即产生空闲中断。
MM32F0270系列的UART支持空闲中断功能。相关的寄存器包括UART中断状态寄存器(UART_ISR)、 UART中断使能寄存器(UART_IER)、 UART中断清除寄存器(UART_ICR),对应的位如下:
UART中断状态寄存器(UART_ISR)
![“MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100556780-238653-1.png)
UART中断使能寄存器(UART_IER)
![“MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100556780-238654-2.png)
UART中断清除寄存器(UART_ICR)
![“MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100556780-238655-3.png)
UART DMA方式
MM32F0270 UART使用DMA方式接收数据可以减小CPU的开销。
对于接收定长数据,可以将DMA接收缓冲区的长度设定为待接收数据的长度,这样利用DMA的传输完成中断就可以知道已经接收了一帧数据。
对于接收不定长数据,由于内核在串口接收数据到空闲这段时间,是不受理串口数据的,所以可以使用DMA来协助我们把数据传送到指定的地方,当数据传输完成后,通知内核去处理。
截取MM32F0270的DMA各通道请求映像表如下,其中UART1_RX对应通道3。
![“各通道DMA请求一览表(部分)"](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100556780-238656-4.png)
实验
本次实验使用UART空闲中断功能,通过DMA方式把数据传送到指定的缓存区。当UART接收完一帧数据后,会产生一个空闲中断。这个中断在UART其他任何状态都不产生,只会在接收完一帧数据后才会产生,一帧数据可以是1个字节或者多个字节。因此,我们可以在这个空闲中断函数中,设置一个接收完成标志位。那么,我们只需要在主程序中检测这个标志位就知道数据是否接收完成了,如果数据接收完成,将数据发送到上位机显示。
程序部分
程序参考官网UART空闲中断代码,并在此基础上修改。
UART初始化
void UART1_NVIC_Init(u32 baudrate) { UART_InitTypeDef UART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2ENR_UART1, ENABLE); //UART1 NVIC NVIC_InitStruct.NVIC_IRQChannel = UART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); //Baud rate UART_StructInit(&UART_InitStruct); UART_InitStruct.BaudRate = baudrate; //The word length is in 8-bit data format. UART_InitStruct.WordLength = UART_WordLength_8b; UART_InitStruct.StopBits = UART_StopBits_1; //No even check bit. UART_InitStruct.Parity = UART_Parity_No; //No hardware data flow control. UART_InitStruct.HWFlowControl = UART_HWFlowControl_None; UART_InitStruct.Mode = UART_Mode_Rx | UART_Mode_Tx; UART_Init(UART1, &UART_InitStruct); UART_Cmd(UART1, ENABLE); UART1_GPIO_Init(); }
DMA初始化
void DMA_Config_Init(DMA_Channel_TypeDef* dam_chx, u32 cpar, u32 cmar, u16 cndtr) { DMA_InitTypeDef DMA_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1, ENABLE); DMA_DeInit(dam_chx); DMA_StructInit(&DMA_InitStruct); DMA_InitStruct.DMA_PeripheralBaseAddr = cpar; DMA_InitStruct.DMA_MemoryBaseAddr = cmar; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStruct.DMA_BufferSize = cndtr; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; DMA_InitStruct.DMA_Priority = DMA_Priority_Low; DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; DMA_InitStruct.DMA_Auto_reload = DMA_Auto_Reload_Disable; DMA_Init(dam_chx, &DMA_InitStruct); UART_DMACmd(UART1, UART_DMAReq_EN, ENABLE); DMA_Cmd(dam_chx, ENABLE); }
在程序中调用DMA初始化函数配置DMA1_Channel3,将UART1接收寄存器的数据通过DMA搬运到接收缓冲区sRecvBuf[RECVBUFLENGTH],数据单元数目为RECVBUFLENGTH。
DMA_Config_Init(DMA1_Channel3, (u32)&UART1->RDR, (u32)sRecvBuf, RECVBUFLENGTH);
UART中断服务函数
void UART1_IRQHandler(void) { /* Omit the code related to sending. */ // Recv packet if (UART_GetITStatus(UARTx, UART_ISR_RX) != RESET) { UART_ClearITPendingBit(UARTx, UART_ICR_RX); if(Flag_RecvComplete == 0) { if(RecvCnt < RECVBUFLENGTH) { //(1) RecvCnt++; } else { RecvCnt = 0; Flag_RecvComplete = 1; //(2) } } } //Idle interrupt if (UART_GetITStatus(UARTx, UART_ISR_RXIDLE) != RESET) { receive_len = RECVBUFLENGTH - DMA_GetCurrDataCounter(DMA1_Channel3); //(3) if(receive_len > 0){ Flag_RecvComplete = 1; //(4) } UART_ClearITPendingBit(UARTx, UART_ICR_RXIDLE); } }
(1)UART接收到数据进入中断,通过变量RecvCnt累加记录接收的数据量。限制RecvCnt不能超出缓冲区范围。
(2)对超出缓冲区数据处理,此处将超出缓冲区的数据舍去,将Flag_RecvComplete置1。
(3)进入UART空闲中断,通过receive_len记录当前DMA传输的数据单元数量。
(4)接收到数据,则将Flag_RecvComplete置1。
在中断外通过判断Flag_RecvComplete标志进行数据处理。
UART收发函数
void UART1_RxTx_Transceiving(void) { UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE); //(1) UART_ITConfig(UART1, UART_IER_RXIDLE, ENABLE); //(2) while(1) { if(Flag_RecvComplete == 1) { //(3) Flag_RecvComplete = 0; memcpy((u8*)&sSendBuf[0], (u8*)&sRecvBuf[0], receive_len); //(4) //DMA reset to reinitialize DMA_Cmd(DMA1_Channel3, DISABLE); DMA_Config_Init(DMA1_Channel3, (u32)&UART1->RDR, (u32)sRecvBuf, RECVBUFLENGTH); //(5) DMA_Cmd(DMA1_Channel3, ENABLE); //Send data UART1_Send_Packet_Interrupt((u8*)&sSendBuf[0], receive_len); // while(1) { if((SendLen) == UART1_Check_Send_Finish()) { break; } } } } }
(1)和(2)配置UART_IT_RXIEN中断和UART_IER_RXIDLE中断。
(3)判断标志位,该标志位在进入空闲中断置1。
(4)将接收缓冲区sRecvBuf的数据复制到发送缓冲区sSendBuf。
(5)复位DMA,重新设置DMA传输的数据单元数目为RECVBUFLENGTH(接收缓冲区范围)。传输数量寄存器DMA_CNDTRx只能在通道关闭时写入,通道开启后该寄存器变为只读。
其余和发送相关的代码是将数据发送到上位机。
演示
仿真运行程序,可以在程序的①、②位置设置断点,并在Watch窗口观测receive_len的值。
![“MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100556780-238657-5.png)
打开串口调试助手发送一帧数据,如:0123456789,程序运行至断点①,UART中断状态寄存器UART_ISR的RXIDLE_INTF位置1,表示进入UART空闲中断。
![“MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100556780-238658-6.png)
继续运行至断点②,RXIDLE_INTF位清0, Watch窗口显示此时receive_len的值为0x0A,和数据帧长度一致。
![“MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100556780-238659-7.png)
继续运行,UART_RecvComplete置1。
重复进行上述操作,每帧数据发送完成都会进入空闲中断。
串口调试助手显示如下:
![“MM32F0270](http://mcu.eetrend.com/files/2022-01/wen_zhang_/100556780-238660-8.png)
实验简单演示了使用MM32F0270的UART空闲中断+ DMA方式接收不定长数据,运行结果和预期一致。
参考Demo程序可登录MindMotion的官网下载MM32F0270库函数和例程:
https://www.mindmotion.com.cn/products/mm32mcu/mm32f/mm32f_mainstream/MM32F0270/
工程路径如下:
~MM32F0270_Samples\LibSamples\UART\UART_idleframe_Interrupt\
来源: 灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100556780-238653-1.png?itok=utkpcb-C)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100556780-238654-2.png?itok=HnFxAPGG)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100556780-238655-3.png?itok=KbVjIZuv)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100556780-238656-4.png?itok=ZZJXH-Si)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100556780-238657-5.png?itok=gKxmhd4m)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100556780-238658-6.png?itok=p8RJNItL)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100556780-238659-7.png?itok=RNye3wsf)
![](https://cdn.eetrend.com/files/styles/solid-pic-270x177/public/2022-01/wen_zhang_/100556780-238660-8.png?itok=L2fq3Y3U)
许多的工业与消费类应用中,越来越多的需要使用低功耗功能,使用定时唤醒,停机减低功耗。灵动微电子推出的MM32F0270系列,支持多种灵活的低功耗模式,还支持LPTIM和LPUART的外设。
本文介绍了如何使用 MM32F0270的LPTIM来实现定时1s从STOP方式的低功耗模式中唤醒。实现使用LPTIM1,在低功耗stop模式下定时1s,1s后将MM32F0270从stop模式唤醒,并且点亮LED灯。
01、MM32F0270 LPTIM的简要介绍
LPTIM即低功耗定时器,得益于其定时器的低功耗。由于 LPTIM 的时钟源具有多样性,因此 LPTIM 能够在所有电源模式(待机模式除外)下保持运行状态。
即使没有内部时钟源, LPTIM 也能运行,可将其用作“脉冲计数器”,这种脉冲计数器在一些特定的应用中十分有用。
LPTIM 可以支持MCU从低功耗STOP模式唤醒,非常适合实现“超时功能”,而且功耗极低。
LPTIM是低功耗产品在低功耗功耗模式下定时的最佳选择。
![“图1](http://mcu.eetrend.com/files/2021-12/wen_zhang_/100556613-237980-1.png)
02、LPTIM 的功能特性
2.1 MM32的LPTIM具有以下特性:
- 16 位递增计数器
- 3-bit 异步时钟预分频器,对应的分频系数分别为 1、2、4、8、16、32、64、128
- 时钟源可选:
- 内部时钟源:LSI_CLK 和 PCLK
- 外部时钟源:LSE_CLK
- 16-bit 比较寄存器和目标值寄存器
- 触发源可选:硬件触发、软件触发
- 输入极性可选
- 外部脉冲计数(无时钟时)
- 低功耗超时唤醒功能
- PWM 输出
2.2 MM32F0270 LPTIM中断
LPTIM 的中断包括:外部触发中断,比较匹配中断, 计数器溢出中断, 当相应的中断使能位打开,发生相应的事件时,产生相应的中断。
需要使用唤醒时,需要使能相应的中断外,还需配置EXTI使能相关的功能。
相关的寄存器与控制状态位的控制与查询,可以参考用户手册。
03、LPTIM 从STOP模式唤醒的软硬件设计
LPTIM是如何控制配置实现定时1s唤醒STOP 模式的呢?
3.1 在库函数版本的样例中可以通过如下顺序初始化LPTIM
a. 使能LPTIM外设时钟;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_LPTIM1, ENABLE);
b. 配置LPTIM的LPTIM_TimeBaseInit_TypeDef结构体中指定的参数;
选择时钟源为LSE 32.768KHz;
选择计数模式为连续计数模式;
时钟分频为DIV1;
LPTIM_TimeBaseStructInit(&init_struct); //Setting LPTIM base init_struct.ClockSource = LPTIM_LSE_Source;//LPTIM_PCLK_Source;//LPTIM_LSI_Source;// init_struct.CountMode = LPTIM_CONTINUOUS_COUNT_Mode; init_struct.OutputMode = LPTIM_NORMAL_WAV_Mode; init_struct.Waveform = LPTIM_AdjustPwmOutput_Mode; init_struct.Polarity = LPTIM_Positive_Wave; init_struct.ClockDivision = LPTIM_CLK_DIV1;
c. 开启LSE 32.768KHz的时钟,等待稳定;
if(init_struct.ClockSource == LPTIM_LSE_Source) { RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE); //RCC->BDCR |= 1 << 24; PWR_BackupAccessCmd(ENABLE); RCC_LSEConfig(RCC_LSE_ON); DelayNop_Ms(1000); while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY)); LPTIM_CLKConfig(LPTIM1, LPTIM_LSE_Source); }
d. 调用函数LPTIM_TimeBaseInit设置参数及比较器值与目标值;
LPTIM_TimeBaseInit(LPTIM1, &init_struct); LPTIM_SetCompare(LPTIM1, arr / 2 - 1); LPTIM_SetTarget(LPTIM1, arr);
在这设定结合时钟源时钟,分频系数与Target值,得到定时1s的定时值。
e. 设定NVIC 参数与EXTI参数;
void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; EXTI_DeInit(); //set EXTI as WFI EXTI_InitStructure.EXTI_Line = EXTI_Line23 ; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt ; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); EXTI_ClearITPendingBit(EXTI_Line23); NVIC_InitStructure.NVIC_IRQChannel = LPTIMER1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
f. 中断相应处理函数
void LPTIMER1_IRQHandler(void) { if(LPTIM_GetITStatus(LPTIM1, LPTIF_OVIF)) { LPTIM_ClearITPendingBit(LPTIM1, LPTIF_COMPIF | LPTIF_TRIGIF | LPTIF_OVIF); EXTI_ClearITPendingBit(EXTI_Line23); LPTIM_ITConfig(LPTIM1, LPTIE_COMPIE | LPTIE_TRIGIE | LPTIE_OVIE, DISABLE); } }
3.2 实现Demo功能的主要函数代码:
void MCU_EnterSTOP_WFI(void) { PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); } void LPTIM_Function_Demo(void) { int i; DelayNop_Init(); LPTIM1_Init(32768 - 1); NVIC_Configuration(); LED1_OFF(); LED1_TOGGLE(); LED1_TOGGLE(); for(i = 0; i < 10; i++) { __NOP();// DelayNop_Ms(2); LED1_TOGGLE(); } LED1_OFF(); LPTIM_ITConfig(LPTIM1, LPTIE_OVIE, ENABLE); for(i = 0; i < 10; i++) { __NOP();// DelayNop_Ms(1); LED2_TOGGLE(); } LED1_OFF(); MCU_EnterSTOP_WFI(); SystemInit(); while (1) { LED3_TOGGLE(); __NOP();// DelayNop_Ms(4); } }
配置好初始化LPTIM与LED闪灯的初始化操作后,执行翻转5次LED灯的操作;
进入STOP 模式。
延时1S后,定时从STOP模式唤醒。
唤醒后继续执行LED闪灯程序。
![“使用MM32F0270](http://mcu.eetrend.com/files/2021-12/wen_zhang_/100556613-237981-2.png)
通过上述的步骤,简单的演示了MM32F0270的LPTIM 定时1s唤醒的功能。
Demo程序可登录MindMotion的官网:
https://www.mindmotion.com.cn/products/mm32mcu/mm32f/mm32f_mainstream/MM32F0270/
下载MM32F0270 lib_Samples,工程路径如下:
~ MM32F0270_Samples\LibSamples\LPTIM\
来源:灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。
![](https://cdn.eetrend.com/files/styles/solid-pic-400x250/public/2021-12/wen_zhang_/100556613-237980-1.png?itok=0mlbtKxg)
![](https://cdn.eetrend.com/files/styles/solid-pic-400x250/public/2021-12/wen_zhang_/100556613-237981-2.png?itok=90D9Eywk)
灵动微电子发布全新主流型 MM32F0270 系列 MCU,目前 LQFP100,LQFP64 和 LQFP48 封装型号已开始接受订单。该系列 MCU 搭载了 Arm® Cortex®-M0 内核,主频高达 96MHz,提供高达 128KB Flash 和 16KB SRAM,并集成了丰富的通信接口、定时器和模拟资源。MM32F0270 系列 MCU 的典型应用包括工业物联网设备、电子门锁控制、医疗和手持设备、PC 和游戏外设等。
![“灵动发布全新主流型MM32F0270系列MCU"](http://mcu.eetrend.com/files/2021-12/wen_zhang_/100556317-231456-1.png)
MM32F0270的主要特点:
- Arm® Cortex®-M0 内核,主频高达 96MHz
- 高达 128KB Flash 和16KB SRAM
- 多达 4 组 UART、1 组低功耗 UART 接口、2 组 SPI、2 组 I2S、2 组 I2C
- 1 组 USB Device FS 2.0 接口
- 1 组 CAN 2.0B 控制器
- 1 组高级定时器,可输出 4 通道带互补端口的 PWM,支持死区和刹车
- 1 组 32 位定时器、6 组 16 位定时器
- 1 组 12-bit 1MSPS SAR ADC,提供多达 14 个外部通道
- 1 组 12-bit DAC
- 2 组高速模拟比较器
- 2.0 – 5.5V 宽压设计,适用于各种电源供电场合
![“灵动发布全新主流型MM32F0270系列MCU"](http://mcu.eetrend.com/files/2021-12/wen_zhang_/100556317-231457-2.jpg)
产品供货情况
MM32F0270现已批量供应 LQFP100、LQFP64 和 LQFP48 三种可选封装形式,全系列配置 128KB Flash,提供 -40~85°C 和 -40~105°C 产品型号,具体选型信息参考数据手册。
有关芯片购买事宜,请洽灵动的销售、官方代理商和方案设计公司。
更多详细信息,请访问 www.mm32mcu.com
来源:灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。
![](https://cdn.eetrend.com/files/styles/solid-pic-400x250/public/2021-12/wen_zhang_/100556317-231456-1.png?itok=QcS8bcOM)
![](https://cdn.eetrend.com/files/styles/solid-pic-400x250/public/2021-12/wen_zhang_/100556317-231457-2.jpg?itok=hIn1qB3e)
![订阅 RSS - MM32F0270](https://cdn.eetrend.com/misc/feed.png)