本帖最后由 lilijin1995 于 2022-12-1 19:39 编辑
各位大佬,大家好,我又来水帖子了,本期给大家带来的是MM32L0136C7P的评估板测试。 哈哈,又是一个玩梗的案子。
2022年11月27日:
基于Systick实现1ms中断
● 开箱晒图: 收到EVB-l0136正是我换了新工作台面的日子,可谓双喜临门!!! 特性介绍: - Arm Cortex-M0+ 内核
- 板载 MM32L0136C7P(LQFP64)
- 外扩 UART、SPI、Micro-USB 接口
- 4 x Key、4 x LED
- 4 x 功能选择开关
- I2S Speaker
- 板载段码 LCD 屏
主控芯片介绍: MM32L0136 微控制器搭载 Arm ® Cortex ® -M0+ 内核,最高工作频率可达 48MHz。内置 64KB 高速存储器,并集成了丰富的 I/O 端口和外设模块。MM32L0136 包含 1 个 12 位的 ADC、 1 个比较器、2 个 16 位通用定时器、2 个 16 位基本定时器、1 个低功耗定时器和 1 个 RTC 计数器,还包含标准的通信接口:2 个 UART 接口、1 个低功耗 UART 接口、2 个 SPI 接 口、2 个 I2S 接口和 1 个 I2C 接口。此外,MM32L0136 还内置了段码式液晶驱动模块(SLCD) 和红外信号调制模块(IRM)。 MM32L0136 工作电压为 1.8V ∼ 5.5V,工作温度范围(环境温度)为 -40°C ∼ +85°C。内置 多种省电工作模式保证低功耗应用的要求。 这些丰富的外设配置,使得本产品微控制器适合于多种应用场合: • 空调遥控器 • 温控器 • 耳、额温枪 • 便携医疗设备 • 气、水、热表 • 小家电 MM32L0136 提供 LQFP64 和 LQFP48 封装形式。 ● 上电测试: 收到后,简单了玩了以下,板子可播放音乐因为有I2S Speak,强!!!并且断码屏也有对应的显示。简单看了以下外设例程
另外有其他应用例程 同时有如下组件 例程可如此丰富,满足了绝大部分应用场景。 ● 搭建开发环境: 软件安装、驱动安装、例程库资源下载。 SDK 软件请从 https://mindsdk.mindmotion.com.cn 下载,需要注册一下 我习惯于使用MDK开发,而使用MDK需要对应的MCU支持包,这里官网可以下载,并且一步到位,提供了多款MCU的。
● 例程测试: 看了多个例程,而且我发现所有例程竟然没有一个例程是基于systick实现delay的,所以我的第一个想法是自己实现一个delay,但前提又是基于Systick需要有一个准确的时基。所以这里先来实现一个准确的1ms的SysTick_Handler。测试的话就用LED2对应的PB9。 首先我创建了一个MyBSP文件夹和代码分组存放我们自己写的代码,以下是Systick.c
#include "Systick.h"
#include "clock_init.h"
#include "board_init.h"
u8 i = 0;
u32 Counter = 0;
void SysTick_Handler(void)
{
Counter++;
if(Counter >= 500) {
Counter = 0;
GPIO_WriteBit(BOARD_LED1_GPIO_PORT, BOARD_LED1_GPIO_PIN, (i == 0) ? (i = 1) : (i = 0)); /* led off. */
}
}
void Systick_init(void)
{
if (SysTick_Config(CLOCK_SYSTICK_FREQ)) {
// Capture error
while (1);
}
// Configure the SysTick handler priority
NVIC_SetPriority(SysTick_IRQn, 0x0);//SysTickinterrupt priority class set
}
其中GPIO_WriteBit(BOARD_LED1_GPIO_PORT, BOARD_LED1_GPIO_PIN, (i == 0) ? (i = 1) : (i = 0))是翻转LED2.
SysTick_Config是系统Tick配置初始化系统计时器及其中断,并启动系统计时计时器。CLOCK_SYSTICK_FREQ是两个中断之间的滴答数如下定义
<font face="楷体, 楷体_GB2312">#define CLOCK_SYS_FREQ 48000000u
#define CLOCK_SYSTICK_FREQ (CLOCK_SYS_FREQ/1000u)</font>
系统时钟是48MHz,Systick=CLOCK_SYS_FREQ/1000 则是配置了1ms中断,即1ms进入SysTick_Handler一次,Counter 自加500次则每500ms翻转一次,也就是说灯闪烁1Hz频率。使用逻辑分析仪测得正是1Hz。
2022年11月28日: 基于Systick实现us与ms延迟
我们上节基于systick实现了1ms中断,我们今天实现两个延迟函数,delayus与delayms。 首先是初始化: #define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB)
这里SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8是选择系统时钟源8分频,所以CLOCK_SYSTICK_FREQ=CLOCK_SYS_FREQ/8000000,最后通过我们在main函数中测试一下。
首先是delayus测试,int main(void)
{
u8 i = 0;
BOARD_Init();
delay_init();
while (1)
{
delay_us(1);
GPIO_WriteBit(BOARD_LED1_GPIO_PORT, BOARD_LED1_GPIO_PIN, (i == 0) ? (i = 1) : (i = 0)); /* led off. */
}
}
目的是翻转LED2,测得时序如下:
可以看到us延迟不准确,然后C语言编译之后指令周期肯定不是1us,但总感觉不是那么准了。这里就不深究了。
接着我们测试ms
<font face="楷体, 楷体_GB2312">int main(void)
{
u8 i = 0;
BOARD_Init();
delay_init();
while (1)
{
delay_ms(1);
GPIO_WriteBit(BOARD_LED1_GPIO_PORT, BOARD_LED1_GPIO_PIN, (i == 0) ? (i = 1) : (i = 0)); /* led off. */
}
}</font>
测得的时序如下,
ms是准的。
2022年11月30日:
3.3.1简介MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。 3.3.2使用方法- 配置系统时间基准接口,安装定时器驱动;
- 实例化一个定时器对象;
- 设置定时时间,超时回调处理函数, 用户上下指针,启动定时器;
- 在主循环调用定时器后台处理函数
3.3.3功能限制 1.定时器的时钟频率直接影响定时器的精确度,尽可能采用1ms/5ms/10ms这几个精度较高的tick;
2.定时器的回调函数内不应执行耗时操作,否则可能因占用过长的时间,导致其他定时器无法正常超时;
3.由于定时器的回调函数是在 MultiTimerYield 内执行的,需要注意栈空间的使用不能过大,否则可能会导致栈溢出。
3.3.4移植到EV Board (MM32L0136C7P) 第一步是配置好时基函数:
u32 Counter = 0;
void SysTick_Handler(void)
{
Counter++;
}
uint32_t HAL_GetTick(void)
{
return Counter;
}
第二步是实例化两个定时器对象,一个用于按键扫描,一个用于控制LED的灯。
MultiTimer timer1;
MultiTimer timer2;
第三步,设置定时时间,超时回调处理函数, 用户上下指针,启动定时器;
static uint8_t keydown=0;
void KeyTimer1Callback(MultiTimer* timer, void *userData)
{
if(GPIO_ReadInDataBit(GPIOD,GPIO_PIN_5)==0)
{
printf("Key0 dowm!\r\n");
keydown=1;
}else{
keydown=0;
printf("Key0 up!\r\n");
}
MultiTimerStart(timer, 10, KeyTimer1Callback, userData);
}
void LEDTimer2Callback(MultiTimer* timer, void *userData)
{
if(keydown==1)
{
GPIO_WriteBit(GPIOB,GPIO_PIN_10,0);
printf("LED ON!\r\n");
}else{
GPIO_WriteBit(GPIOB,GPIO_PIN_10,1);
printf("LED OFF!\r\n");
}
MultiTimerStart(timer, 10, LEDTimer2Callback, userData);
}
最后,在主循环调用定时器后台处理函数
int main(void)
{
u8 i = 0;
BOARD_Init();
Systick_init();
MultiTimerInstall(PlatformTicksGetFunc);
MultiTimerStart(&timer1, 5, KeyTimer1Callback, NULL);
MultiTimerStart(&timer2, 10, LEDTimer2Callback, NULL);
while (1)
{
MultiTimerYield();
}
}
|