五、定时器实现呼吸灯

5.1 定时器与计数器简介

        定时器是一种通过对内部时钟脉冲计数来测量时间间隔的模块。它的核心是一个递增或递减的寄存器(计数器值)。如果系统时钟为 1 MHz,定时器每 1 μs 计数一次。

        计数器是一种对外部事件(如脉冲信号)进行计数的模块,而不是基于固定时钟。外部引脚每收到一个脉冲(如按键按下或传感器触发),计数值加 1 或减 1。

        LPC1100系列Cortex-M0微控制器有2个32位和2个16位可编程定时器/计数器,都有捕获和匹配输出的功能。

        捕获:捕获功能用于记录外部信号变化时定时器的当前值,常用于测量信号的频率、脉宽或相位差。当外部信号(如引脚电平变化)触发捕获事件时,定时器的当前值会被自动保存到捕获寄存器。

        匹配输出:定时器的一种功能,当定时器的计数值达到预设的匹配值(Match Value)时,自动触发特定动作(如翻转引脚电平、产生中断等)。用户预先设置一个匹配值,当定时器计数值等于该值时,硬件会自动执行操作,无需 CPU 干预。

5.2 定时器工作流程

        对于定时器,先设置预分频计数器的计数上限,预分频计数器每计满一次定时器就加一,定时器达到匹配就可触发相应事件。

        设置 PR (分频值)的值(如 PR = 99),PC 从 0 开始计数。每来一个输入时钟脉冲,PC 加 1。当 PC = PR 时,PC 清零,并输出一个脉冲给定时器的主计数器。每接收到一个来自预分频器的脉冲,定时器的主计数器TC加 1。

5.3 定时器/计数器寄存器         

        有四种定时器 TMR32B0、TMR32B1、TMR16B0, TMR16B1

        功能类似,就计的总数32位、16位的区别

5.3.1 定时器中断寄存器 TMR32/16BnIR

包含4个匹配中断和一个捕获中断标志位,有中断相应位置位变成1,没中断变0,写1可以清零中断,写零无效。

对应名
0

MR0中断

中断标志
1MR1中断
2MR2中断
3MR3中断
4

CAP0中断

31:5保留

5.3.2 定时器控制寄存器 TMR32/16BnTCR

功能
0

1使能,0禁能

1

        写1定时器/计数器和分频在PCLK下一个上升沿复位,

        复位状态直到该位重新写0才会改变

31:2保留

5.3.3 定时器/计数器当前计数值 TMR32/16BnTC

        预分频计数器计数到上限时,TC计数值加一,TC到上限没复位则32位会计数到0xFFFFFFFF然后翻转到0x00000000,没中断啥的一些情况,然后继续去计数了。

5.3.4 预分频寄存器 TMR32/16BnPR

        指定预分频计数器的最大计数值

        PR为0,每1个PCLK(48MHz时钟一个周期)TC计数加一

        PR为1,每2个PCLKTC计数加一

5.3.5 预分频计数器 TMR32/16BnPC

        对输入时钟脉冲进行计数的计数值,不用理会

5.3.6 匹配控制寄存器 TMR32/16BnMCR

        

功能 (1 产生对应效果, 0 无该特性)

0

MR0匹配时产生中断
1MR0匹配时复位TC
2MR0匹配时TC和PC计数都停止 TCR[0]置0(定时器禁能了)
3MR1匹配时产生中断
4MR1匹配时复位TC
5MR1匹配时TC和PC计数都停止 TCR[0]置0(定时器禁能了)
6MR2匹配时产生中断
7MR2匹配时复位TC
8MR2匹配时TC和PC计数都停止 TCR[0]置0(定时器禁能了)
9MR3匹配时产生中断
10MR3匹配时复位TC
11MR3匹配时TC和PC计数都停止 TCR[0]置0(定时器禁能了)
31:12保留

5.3.7 匹配寄存器 TMR32/16BnMR0/1/2/3

        自动与TC值相比较的,相等触发对应效果,不用理会

5.3.8 捕获寄存器 TMR32/16BnCCR

功能 (1 产生对应效果, 0 无该特性)

0

CAP0上升沿捕获,使TC内容装入CR0
1CAP0下降沿捕获,使TC内容装入CR0
2CAP0事件导致的装载产生中断
31:3保留

5.3.9 捕获寄存器 TMR32/16BnCR0

        引脚发生特定事件时存储TC内容,只读

5.3.10 外部匹配寄存器 TMR32/16BnEMR

功能
0

EM0外部匹配0输出MAT0的状态

即TC与MR0匹配时的输出

1EM1外部匹配1输出MAT1的状态
2EM2外部匹配0输出MAT2的状态
3EM3外部匹配0输出MAT3的状态
5:4

EMC0

00 无操作

01 输出低电平0

10 输出高电平1

11 输出电平翻转

7:6EMC1  以下同EMC0
9:8EMC2
10:11EMC3
15:12保留

5.3.11 计数控制寄存器 TMR32/16BnCTCR

        用于定时器与计数器模式之间的选择

描述
1:000定时器模式:TC在PCLK上升沿计数
01计数器模式:TC在选择的CAP输入的上升沿递增
10计数器模式:TC在选择的CAP输入的下降沿递增
11计数器模式:TC在选择的CAP输入的双边沿递增
3:200CAP0引脚
其他保留(貌似条件有限没有其他CAP引脚,所以上边选择也是就选择CAP0)
31:4保留

5.3.12 PWM控制寄存器 TMR32/16BnPWMC

        用于将匹配的输出设置为PWM输出,

        大致可整两个匹配,分别控制占空比和周期

        一个匹配寄存器调占空比,出现匹配时,PWM输出置为高电平,匹配前是低电平

        一个匹配作为PWM周期,匹配时复位,高电平清零

        具体小细节见书P136页。

功能
0

1 MAT0的PWM模式使能

0 MAT0受EM0控制

1

1 MAT1的PWM模式使能

0 MAT1受EM1控制

2

1 MAT2的PWM模式使能

0 MAT2受EM2控制

3

1 MAT3的PWM模式使能

0 MAT3受EM3控制

32:4保留

5.4 呼吸灯

目标:

(1)利用16位定时器1实现定时1s,控制LPC1114微控制器的GPIO引脚PIO1_9状态反转(可以用中断方式也可以用匹配输出功能),此时LED灯Blinky闪烁频率为0.5Hz;

(2)设置16位定时器1工作在PWM模式,PIO1_9设置为PWM输出引脚,利用另外一个定时器定时(例如32位定时器0,设置每隔0.01s,或者更小)增大或者减小16位定时器1输出PWM的占空比(占空比改变的步长与32位定时器0的定时时间相配合,确定呼吸频率),实现PIO1_9上的LED灯渐亮渐灭的呼吸灯效果。

思路:

        主要是两部分内容,第一部分直接SysTick也能实现,但是使用定时器就是要熟悉一下定时器怎么用,第二部分就是定时器的PWM占空比不断升高降低,这个是使用两个定时器,一个定时器实现翻转,另一个定时器实现改变第一个定时器的占空比,按时间依次增加或者减小即可。

         这两部分内容可以直接使用按键切换,相当于两种模式,即闪烁模式和PWM呼吸灯模式,将上章写的Button中断改一下就行了

Button.c

#include "Button.h"
#include "TIMER.h"
int flag1 = 0, flag2 = 0; // 判断botton 和 wakeup 按键上一次状态

//延时ms函数 // 太粗糙了,而且要根据机器指令与时钟周期关系调整,也就防抖延时用一下
__inline void delay_ms(uint32_t a)    //约1ms延时函数 
{                           
    uint32_t i;
    while( a -- != 0)
    {
           for(i = 0; i<5500; i++);
    }             
}

void WAKEUP_Init(void)
{
	LPC_SYSCON -> SYSAHBCLKCTRL |= (1UL << 6) | (1UL << 16); // 使能GPIO时钟和IO时钟
	// PIO1_4
    LPC_IOCON->PIO1_4 &= ~(0x1F);  // 清除之前的配置
    LPC_IOCON->PIO1_4 |= 0x00;     // 配置为GPIO功能
    LPC_GPIO1->DIR &= ~(1UL << 4);// 设置GPIO方向为输入
	
    LPC_GPIO1->IS &= ~(0x1 << 4); // 清除第 4 位,设置为边沿触发
    LPC_GPIO1->IBE &= ~(0x1 << 4); // 清除第 4 位,设置为单边沿触发
    LPC_GPIO1->IEV &= ~(0x1 << 4); // 清除第 4 位,设置为低电平触发
	LPC_GPIO1 -> IE |= (0x1<<4); // 使能端口中断
	LPC_IOCON->PIO1_4 |= (1UL << 5);          // 使能滞后模式
    LPC_GPIO1->IC |= (1UL << 4); // 清除中断标志位
    NVIC_EnableIRQ(EINT1_IRQn); // 使能GPIO1中断
}

void Button_Init(void)
{
	LPC_SYSCON -> SYSAHBCLKCTRL |= (1UL << 6) | (1UL << 16); // 使能GPIO时钟和IO时钟
	// PIO3_5
    LPC_IOCON->PIO3_5 &= ~(0x1F);   // 清除之前的配置
    LPC_IOCON->PIO3_5 |= 0x00;      // 配置为GPIO功能
    LPC_GPIO3->DIR &= ~(1UL << 5);// 设置GPIO方向为输入
	
    LPC_GPIO3->IS &= ~(0x1 << 5); // 清除第 5 位,设置为边沿触发
    LPC_GPIO3->IBE &= ~(0x1 << 5); // 清除第 5 位,设置为单边沿触发
    LPC_GPIO3->IEV &= ~(0x1 << 5); // 清除第 5 位,设置为低电平触发
    LPC_GPIO3 -> IE |= (0x1<<5); // 使能端口中断
	LPC_IOCON->PIO3_5 |= (1UL << 5);  // 使能滞后模式
    LPC_GPIO3->IC |= (1UL << 5); //清除中断标志
    NVIC_EnableIRQ(EINT3_IRQn);
}

// GPIO3_5的中断服务函数,处理BUTTON按键按下事件
void PIOINT3_IRQHandler(void)
{
    if((LPC_GPIO3->MIS & (1UL << 5)) == (1UL << 5))// 检查是否是PIO3_5的中断
	{ 
		delay_ms(20); // 消抖
		while((LPC_GPIO3->DATA & (1UL << 5)) == 0);
		delay_ms(20);
	

            
            LPC_TMR16B1->PWMC ^= 1; //PWM状态翻转
            if(LPC_TMR16B1->PWMC == 0x01) // 如果要进PWM 模式
            {
                NVIC_EnableIRQ(TIMER_32_0_IRQn);//使能32位定时器中断
                TMR16B1_PWM_Mode();  
            }
            else    // 如果要进闪烁灯模式
            {
                NVIC_DisableIRQ(TIMER_32_0_IRQn);//禁32位定时器中断
                TMR16B1_Blinky_Mode();
            }
         
		
		LPC_GPIO3->IC |= (1UL << 5);          // 清除中断标志
    }
}
// GPIO1_4的中断服务函数,处理WAKEUP按键按下事件
void PIOINT1_IRQHandler(void)
{
    if((LPC_GPIO1->MIS & (1UL << 4)) == (1UL << 4)) // 检查是否是PIO1_4的中断
	{
		delay_ms(20);
		while((LPC_GPIO1->DATA & (1UL << 4)) == 0);
		delay_ms(20);

		
        LPC_GPIO1->IC |= (1UL << 4);           // 清除中断标志
    }
}

TIMER.c

#include "TIMER.h"

int flag = 1; // 递增递减标志 1递增 -1递减

void TMR32B0_Init(void)//32位定时器0初始化  设置中断时间 MR0/SystemCoreClock *(PR + 1) = 0.01s
{
	LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 9);//使能32位定时器0的时钟
	LPC_TMR32B0->IR = 0x1F;//清除所有中断标志位
	LPC_TMR32B0->PR = 0;//设置分频系数
	LPC_TMR32B0->MCR = 3;//设置MR0匹配后复位TC并产生中断
	LPC_TMR32B0->MR0 = SystemCoreClock / 100 ; // 计数值
	LPC_TMR32B0->TCR = 0x01;//启动定时器
	NVIC_DisableIRQ(TIMER_32_0_IRQn);//开中断
}

void TMR16B1_Init(void)
{
    LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 8) | (1UL << 16); // 16位定时器1时钟使能 | IO配置块时钟使能
    LPC_IOCON->PIO1_9 |= 0x01; // MAT0匹配IO1_9    
}

void TMR16B1_PWM_Mode(void)// PWM呼吸灯模式 1s 占空比0 -> 1 or 1 -> 0
{
    LPC_TMR16B1->TCR = 0x02;//定时器复位
    LPC_TMR16B1->PR = 99; // 分频系数
    LPC_TMR16B1->PWMC = 0x01;//设置MAT0为PWM输出
    LPC_TMR16B1->MCR = 0x02 << 9; //设置MR3匹配后复位TC;
    LPC_TMR16B1->MR3 = SystemCoreClock / 10000; // PWM周期设置为0.01s,设置中断时间
    LPC_TMR16B1->MR0 = LPC_TMR16B1->MR3 / 100;//MAT0初始化输出亮度1%
    LPC_TMR16B1->TCR = 0x01; // 启动定时器
}

// 匹配输出翻转
void TMR16B1_Blinky_Mode(void) // 闪烁灯模式 1s翻转一次
{    
    LPC_TMR16B1->TCR = 0x02;//定时器复位
    LPC_TMR16B1->PR = 999; // 分频系数;
    LPC_TMR16B1->MCR = 2; // 设置MR0匹配后复位TC不产生中断;
    LPC_TMR16B1->MR0 = SystemCoreClock / 1000; // 定时1s
    LPC_TMR16B1->PWMC = 0x00;//设置MAT0不为PWM输出
    LPC_TMR16B1->EMR |= (3UL << 4);// MAT0外部匹配翻转
    
    LPC_TMR16B1->TCR = 0x01; //定时器启动
}

void TIMER32_0_IRQHandler(void)//32位定时器0中断子程序
{
    static int duty = 0;
    if(LPC_TMR32B0->IR & 0x01)//判断是否MR0中断
    {
        LPC_TMR32B0->IR = 0x01; // 清除第一中断标志位
        
        duty += 1 * flag; // 更新占空比
        if(duty >= 100) 
        {
            flag = -flag; // 递减 渐灭
            duty = 100; // 防止越界
        }
        if(duty <= 0) 
        {
            flag = -flag; // 递增 渐亮
            duty = 1; // 防止越界
        }
        LPC_TMR16B1->MR0 = (uint32_t)(LPC_TMR16B1->MR3 * duty /100); // 设置占空比
    }    
}

TIMER.h

#ifndef _TIMER_H_
#define _TIMER_H_

#include <LPC11xx.h>

void TMR32B0_Init(void);
void TMR16B1_Init(void);
void TMR16B1_PWM_Mode(void);
void TMR16B1_Blinky_Mode(void);

#endif

main.c

#include <LPC11xx.h>
#include "LED.h"
#include "Button.h"
#include "TIMER.h"


int main(void)
{
	Button_Init(); // Button初始化
    TMR16B1_Init(); //初始化16位B1定时器
    TMR32B0_Init(); // 初始化32位B0定时器
    TMR16B1_Blinky_Mode(); // 初始闪烁灯模式
    
    
    while (1)
    {

    }
}

        实验效果就是烧录后按下复位键,Blinky开始闪烁,按下Button是PWM,之后再按就会在两种模式之间切换。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/963919.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#,shell32 + 调用控制面板项(.Cpl)实现“新建快捷方式对话框”(全网首发)

Made By 于子轩&#xff0c;2025.2.2 不管是使用System.IO命名空间下的File类来创建快捷方式文件&#xff0c;或是使用Windows Script Host对象创建快捷方式&#xff0c;亦或是使用Shell32对象创建快捷方式&#xff0c;都对用户很不友好&#xff0c;今天小编为大家带来一种全新…

DDD - 微服务架构模型_领域驱动设计(DDD)分层架构 vs 整洁架构(洋葱架构) vs 六边形架构(端口-适配器架构)

文章目录 引言1. 概述2. 领域驱动设计&#xff08;DDD&#xff09;分层架构模型2.1 DDD的核心概念2.2 DDD架构分层解析 3. 整洁架构&#xff1a;洋葱架构与依赖倒置3.1 整洁架构的核心思想3.2 整洁架构的层次结构 4. 六边形架构&#xff1a;解耦核心业务与外部系统4.1 六边形架…

基于SpringBoot的新闻资讯系统的设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

xmind使用教程

xmind使用教程 前言xmind版本信息“xmind使用教程”的xmind思维导图 前言 首先xmind是什么&#xff1f;XMind 是一款思维导图和头脑风暴工具&#xff0c;用于帮助用户组织和可视化思维、创意和信息。它允许用户通过图形化的方式来创建、整理和分享思维导图&#xff0c;可以用于…

半导体器件与物理篇7 微波二极管、量子效应和热电子器件

基本微波技术 微波频率&#xff1a;微波频率涵盖约从0.1GHz到3000GHz&#xff0c;相当于波长从300cm到0.01cm。 分布效应&#xff1a;电子部件在微波频率&#xff0c;与其在较低频率的工作行为不同。 输运线&#xff1a;一个由电阻、电容、电感三种等效基本电路部件所组成的…

Java自定义IO密集型和CPU密集型线程池

文章目录 前言线程池各类场景描述常见场景案例设计思路公共类自定义工厂类-MyThreadFactory自定义拒绝策略-RejectedExecutionHandlerFactory自定义阻塞队列-TaskQueue&#xff08;实现 核心线程->最大线程数->队列&#xff09; 场景1&#xff1a;CPU密集型场景思路&…

浅谈线段树

文章同步发布于洛谷&#xff0c;建议前往洛谷查看。 前言 蒟蒻终于学会线段树&#xff08;指【模板】线段树 1 1 1&#xff09;啦&#xff01; 线段树思想 我们先来考虑 P3372&#xff08;基础线段树模板题&#xff09;给的操作&#xff1a; 区间修改&#xff08;增加&am…

linux运行级别

运行级别&#xff1a;指linux系统在启动和运行过程中所处的不同的状态。 运行级别之间的切换&#xff1a;init (级别数) 示例&#xff1a; linux的运行级别一共有7种&#xff0c;分别是&#xff1a; 运行级别0&#xff1a;停机状态 运行级别1&#xff1a;单用户模式/救援模式…

【自开发工具介绍】SQLSERVER的ImpDp和ExpDp工具03

SQLSERVER的ImpDp和ExpDp工具 1、全部的表导出&#xff08;仅表结构导出&#xff09; 2、导出的表结构&#xff0c;导入到新的数据库 导入前&#xff0c;test3数据没有任何表 导入 导入结果确认&#xff1a;表都被做成&#xff0c;但是没有数据 3、全部的表导出&#x…

商品列表及商品详情展示

前言 本文将展示一段结合 HTML、CSS 和 JavaScript 的代码&#xff0c;实现了一个简单的商品展示页面及商品详情&#xff0c;涵盖数据获取、渲染、搜索及排序等功能。 效果展示 点击不同的商品会展示对应的商品详情。 代码部分 代码总体实现 <!DOCTYPE html> <htm…

c++提取矩形区域图像的梯度并拟合直线

c提取旋转矩形区域的边缘最强梯度点&#xff0c;并拟合直线 #include <opencv2/opencv.hpp> #include <iostream> #include <vector>using namespace cv; using namespace std;int main() {// 加载图像Mat img imread("image.jpg", IMREAD_GRAYS…

独立开发浏览器插件:案例与启示

浏览器插件&#xff08;Browser Extension&#xff09;作为提升用户浏览体验的重要工具&#xff0c;近年来吸引了许多独立开发者的关注。从广告拦截到生产力工具&#xff0c;再到个性化定制功能&#xff0c;浏览器插件的开发为个人开发者提供了一个低成本、高潜力的创业机会。本…

Linux系统 环境变量

环境变量 写在前面概念查看环境变量main函数的参数argc & argvenv bash环境变量 写在前面 对于环境变量&#xff0c;本篇主要介绍基本概念及三四个环境变量 —— PATH、HOME、PWD。其中 PATH 作为 “ 敲门砖 ”&#xff0c;我们会更详细讲解&#xff1b;理解环境变量的全局…

BFS(广度优先搜索)——搜索算法

BFS&#xff0c;也就是广度&#xff08;宽度&#xff09;优先搜索&#xff0c;二叉树的层序遍历就是一个BFS的过程。而前、中、后序遍历则是DFS&#xff08;深度优先搜索&#xff09;。从字面意思也很好理解&#xff0c;DFS就是一条路走到黑&#xff0c;BFS则是一层一层地展开。…

SpringCloud基础二(完结)

HTTP客户端Feign 在SpringCloud基础一中&#xff0c;我们利用RestTemplate结合服务注册与发现来发起远程调用的代码如下&#xff1a; String url "http://userservice/user/" order.getUserId(); User user restTemplate.getForObject(url, User.class);以上代码就…

Spring Bean 容器

技术成长&#xff0c;是对场景设计细节不断的雕刻&#xff01; 你觉得自己的技术什么时候得到了快速的提高&#xff0c;是CRUD写的多了以后吗&#xff1f;想都不要想&#xff0c;绝对不可能&#xff01;CRUD写的再多也只是能满足你作为一个搬砖工具人&#xff0c;敲击少逻辑流…

【react+redux】 react使用redux相关内容

首先说一下&#xff0c;文章中所提及的内容都是我自己的个人理解&#xff0c;是我理逻辑的时候&#xff0c;自我说服的方式&#xff0c;如果有问题有补充欢迎在评论区指出。 一、场景描述 为什么在react里面要使用redux&#xff0c;我的理解是因为想要使组件之间的通信更便捷…

利用腾讯云cloud studio云端免费部署deepseek-R1

1. cloud studio 1.1 cloud studio介绍 Cloud Studio&#xff08;云端 IDE&#xff09;是基于浏览器的集成式开发环境&#xff0c;为开发者提供了一个稳定的云端工作站。支持CPU与GPU的访问。用户在使用 Cloud Studio 时无需安装&#xff0c;随时随地打开浏览器即可使用。Clo…

基于VMware的ubuntu与vscode建立ssh连接

1.首先安装openssh服务 sudo apt update sudo apt install openssh-server -y 2.启动并检查ssh服务状态 到这里可以按q退出 之后输入命令 &#xff1a; ip a 红色挡住的部分就是我们要的地址&#xff0c;这里就不展示了哈 3.配置vscode 打开vscode 搜索并安装&#xff1a;…

四川正熠法律咨询有限公司正规吗可信吗?

在纷繁复杂的法律环境中&#xff0c;寻找一家值得信赖的法律服务机构是每一个企业和个人不可或缺的需求。四川正熠法律咨询有限公司&#xff0c;作为西南地区备受瞩目的法律服务提供者&#xff0c;以其专注、专业和高效的法律服务&#xff0c;成为众多客户心中的首选。 正熠法…