lilijin1995 发表于 2022-11-27 20:36

【EV Board (MM32L0136C7P)测评】玩透基于Systick的多种应用

本帖最后由 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();
    }
}







cemaj 发表于 2022-12-6 13:24

Systick的功能确实强大很多。

lihuami 发表于 2022-12-6 17:26

Systick基准时钟的代表            

yeates333 发表于 2022-12-6 17:47

可以做延时函数的。            

sanfuzi 发表于 2022-12-12 11:51

还是使用定时器比较好一些。            

robertesth 发表于 2022-12-12 13:41

MM32L0136C7P的systick如何作为驱动时钟?
页: [1]
查看完整版本: 【EV Board (MM32L0136C7P)测评】玩透基于Systick的多种应用