【linux-IMX6ULL-定时器-GPT-串口配置流程-思路】

news2024/9/21 18:51:07

目录

  • 1. 定时器配置流程
    • 1.1 EPIT定时器简介
    • 1.2 定时器1(epit1)的配置流程
    • 1.3 配置代码(寄存器版本)
    • 1.4 定时器-配合按键消抖
      • 1.4.1 实现原理
      • 1.4.2 代码实现(寄存器版)
  • 2. GPT定时器实现高精度延时
    • 2.1 延时原理分析
    • 2.2 代码实现
  • 3. UART串口配置流程
    • 3.1 UART串口通信基本概念;
      • 3.1.1 基本术语
      • 3.1.2 接线方式
      • 3.1.3 UART通信协议
    • 3.2 配置流程
    • 3.3 程序实现(寄存器版)

个人学习记录,下面这些都属于外设的基本配置,一般就是跟寄存器打交道,而配置思路也是大同小异

1. 定时器配置流程

1.1 EPIT定时器简介

  EPIT 的全称是:Enhanced Periodic Interrupt Timer,直译过来就是增强的周期中断定时器,定时器顾名思义就是记时的,对于其他的单片机例如是STM32而言,定时器具备输入捕获和配置PWM输出的功能,但是对于IMX6ULL的EPIT而言就一个定时的功能,比较简单。
  具体的功能可产靠数据手册的秒描述,这里简述几个重要的点:

  • 时钟源可选的 32 位向下计数器
  • 12 位的分频值
  • 当计数值和比较值相等的时候产生中断

1.2 定时器1(epit1)的配置流程

在这里插入图片描述

  1. 初始化定时器:设计定时器相应的寄存器配置,例如时钟源、分频系数、计数重装值、计数初值等:
  2. 使能定时器:这个对于很多外设都是如此,如歌配置好了初始化基本都要进行使能进行工作;
  3. 使能GIC中断服务控制器:开启中断
  4. 对中断服务函数进行注册:中断注册函数的内容可以具体里哦阿姐在IMX6ULL的中断服务系统;
  5. 编写中断服务函数的内容:这个的注意事项就是完成中断任务后要进行中断标志位的清除;

1.3 配置代码(寄存器版本)

/*初始化EPIT定时器函数*/
void epit1_init(unsigned int frac,unsigned int lodvalue)
{
    if(frac>4095)
    {
        frac =4095;
    }
    /*配置控制寄存器CR*/
    EPIT1->CR =0;/*清零*/
    EPIT1->CR = (1<<1)|(1<<2)|(1<<3)|(frac<<4)|(1<<24);
    EPIT1->LR = lodvalue;/*加载寄存器的值,相当于到计数值*/
    EPIT1->CMPR = 0;/*计数器从lodvalue计数到0的话就触发中断*/
    /*初始化中断,使能中中断*/
    GIC_EnableIRQ(EPIT1_IRQn);
    system_register_irqhandler(EPIT1_IRQn,epit1_irqhandler,NULL);/*中断ID,中断服务函数,给中断服务函数传递的参数*/
    /*打开EPIT定时器*/
    EPIT1->CR |=(1<<0);
}
/*中断服务函数的编写*/
 void  epit1_irqhandler(unsigned int gicciar,void *param)
 {
    static unsigned  char state = 0;
    state = !state;
    if(EPIT1->SR&(1<<0))//判断最后一位是不是0,如果为真表示中断发生
    {
        led_switch(LED0,state);/*反转LED0灯*/
    }
    /*清除标志位*/
    EPIT1->SR=1;/*写清零,中断标志位*/
 }

1.4 定时器-配合按键消抖

  对于按键的输入检测,我们之前常用的就是延时消抖,比如延时10ms,然后再次进行确定,但是这样做对于整个程序的效率有很大的影响,这10ms系统只是单纯的在进行无意义的等待,而且延时也不能放在中断中,因为因为中断服务函数最基本的要求就是快进快出!在实际开发中这是要避免发生的;我们可以考虑使用一个定时器和按键输入中断触发来实现按键的消抖;

1.4.1 实现原理

  本质而言还是延时的思想,不过我们把延时这一做法用定时器来实现(当然不是在定时器中进行延时):具体的思路就是定时器在计时的过程中,CPU是可以干其他的工作的,因此定一个10ms的定时器,每当按键触发中断时,定时器就开启,这样等定时器计数到10ms后就会开启定时器的中断,然后我们在定时器的中断中确定按键是否按下,这样就实现了CPU无意义的消耗;示意图如下:它的精髓是按键在前期会有抖动,但是每次抖动都会进入中断把定时器初始化进行重启,因此进行10ms的定时是完全足够的;而定时器在计时的过程中CPU可以处理其他的事情
在这里插入图片描述

1.4.2 代码实现(寄存器版)

  其中定时器的配置流程和上述是一致的,其中按键中断的配置流程可以参考上篇中断配置流程思路,对于中断的配置是底层比较难写,但是对于上层而言只是调用库函数,因此是比较好些的,只要掌握其配置的流程思路就可以的;具体代码如下:无论那种配置都要进行使能和初始化这是每个外设都基本要进行的操作;

/*初始化按键中断*/
void keyfilter_init(void)
{
    gpio_pin_config_t key_config;
    IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);
    IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080);
    key_config.direction=kGPIO_DigitalInput;
    key_config.interruptMode=kGPIO_IntFallingEdge;  //注意这里错误
    //错误设置成低电平触发:导致按键按下去频繁进入中断
    //key_config.interruptMode=kGPIO_IntLowLevel
    key_config.outputLogic = 1;
    gpio_init(GPIO1,18,&key_config);
    GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);
    system_register_irqhandler(GPIO1_Combined_16_31_IRQn,gpio1_io16_31_irqhandlder,NULL);
    gpio_enable_int(GPIO1,18);
    /*初始化定时器*/
    filtertimer_init(66000000/100);
}
/*初始化EPI1定时器*/
void filtertimer_init(unsigned int value)
{
    EPIT1->CR = 0;/*先清零*/
    EPIT1->CR = (1<<1)|(1<<2)|(1<<3)|(1<<24);/*不分频*/
    EPIT1->LR = value;/*加载寄存器的值,相当于到计数值*/
    EPIT1->CMPR = 0;/*计数器从lodvalue计数到0的话就触发中断*/
    /*初始化中断,使能中中断*/
    GIC_EnableIRQ(EPIT1_IRQn);

    system_register_irqhandler(EPIT1_IRQn,filtertimer_irqhandler,NULL);/*中断ID,中断服务函数,给中断服务函数传递的参数*/
}
/*关闭EPIT1定时器*/
void filtertimer_stop(void)
{
    EPIT1->CR &= ~(1<<0);
}
/*重启EPIT1定时器*/
void filtertimer_restart(unsigned int value)
{
    EPIT1->CR &= ~(1<<0);//先关闭
    EPIT1->LR = value;   //装载值
    EPIT1->CR |= (1<<0);//再打开
}
/*注册EPIT1定时器中断处理函数*/
void filtertimer_irqhandler(unsigned int gicciar,void *param)
{
    static unsigned char state = 0;

    if(EPIT1->SR & (1<<0))
    {
        /*关闭定时器*/
        filtertimer_stop();
        if(gpio_pinread(GPIO1,18)==0)
        {
            state = ! state;
            beep_switch(state);
        }
    }
    EPIT1->SR |= 1<<0;        /*写1清除中断标志位*/

}
/*按键中断服务函数*/
void gpio1_io16_31_irqhandlder(unsigned int gicciar,void *param)
{
    /*开启定时器*/
    filtertimer_restart(66000000/100);/*打开EPIT定时器*/
    /*清除中断标志位*/
    gpio_clearintflags(GPIO1,18);

}

2. GPT定时器实现高精度延时

  对于IMX6ULL而言:GPTGPT 定时器全称为 General Purpose Timer,GPT是一个32位的向上计数器,是通用的定时器,同时具备一个12位的分频器(不是只能进行12分频);他的基本特性如下所示:

  1. 一个可选时钟源的 32 位向上计数器。
  2. 两个输入捕获通道,可以设置触发方式。
  3. 三个输出比较通道,可以设置输出模式。
  4. 可以生成捕获中断、比较中断和溢出中断。
  5. 计数器可以运行在重新启动(restart)或(自由运行)free-run 模式。但是一般就是用作重装载模式

2.1 延时原理分析

  本质上还是利用定时器计数的原理,只不过这里的计时是进行增量计时法。例如对于GPT定时器而言,其时钟源是66MHz的,对齐进行66分频后就是1Mhz,也就是计数器寄存器CNT计数一次,时间就过去了1us,因此我们可以可以让中国CNT计数器一直进行计数,每次进入到延时函数就把这次的CNT记录下来例如此时是100,然后我们要延时200,那么我们要做的就是等到CNT==300时我们再出延时函数,这样就实现了延时的效果,但是可能会出现溢出的情况,因此我们要再延时函数中对溢出情况i进行处理,具体的实现如下:注意,在进入延时函数前定时器就是一直再走,因此进入延时函数时定时器也在走,并且运行延时的每行代码定时器都走,因此这里的计时是增量计时法

2.2 代码实现

在这里插入图片描述

3. UART串口配置流程

3.1 UART串口通信基本概念;

3.1.1 基本术语

  1. 串行:就是数据一位一位的顺序传递;
  2. 异步通信:比如A和B通信,那么异步通信就是两边都要设置时钟且保持一致,如果保持不一致就可能会发生数据传输失败;
  3. 同步通信:顾名思义就是通信设备A和B是共用一条时钟线路,保持同步;
  4. 半双工:可以这样理解,工作一半,也就是发送数据和接受数据只能一时进行一个,也就是同一时间只能发数据或者收数据;
  5. 全双工:这个与半双工是相反的,即同一时间发送和接收数据是通一时间进行的;
  • 我们明白上面的概念后,就可以对串口通信UART进行一个定义:串口通信就是串行异步全双工的通信方式
  1. UART和USART的区别:USART指比UART多了一条时钟线,因此可以进行同步通信;但是相对而言,还是串口通信用的范围广泛一些;

3.1.2 接线方式

  一般而言就是四根线进行通信:但是最少可以三根线首先通信,如果是三根线的话只能其中一个设备只能收数据或者只能发数据;注意RX是与TX接线的,因为一个设备发送送数据,另外一个设备肯定是接受数据的;

3.1.3 UART通信协议

  任何通信都要进行约定好了才能通信,因此通信协议就是通信双方进行的一个约定,这个约定一般有起始位(低电平),数据为,奇偶校验位,停止位(高脉冲),示意图如下:一般对于串口通信而言是先发送低位后发送高位,也就是低位在前,高位在后;如下图:

  小知识点,如何进行奇偶校验:可以利用异或的功能,具体描述如下: 我们使用异或来判断一个二进制数中1的数量是奇数还是偶数异或具有交换律,所以判断101001中的1是奇数还是偶数,只用看:1 ^0 ^ 1 ^ 0 ^ 0 ^ 1的最终结果是1还是0,因为其具有交换律,所以 1 ^0 ^ 1 ^ 0 ^ 0 ^ 1=1 ^ 1 ^ 1 ^ 0 ^ 0 ^ 0 =1 ^ 1 ^ 1 = 1 ^ 0 = 1;因此结果是0就是偶数个,结果为1就是奇数个;

3.2 配置流程

  对于UART而言,其也是一个外设,因此对于外设UASRT的配置一般大体思路如下:注意再接受和发送数据时要进行检测是否空闲或者是否有数据可以接收
在这里插入图片描述

3.3 程序实现(寄存器版)

  

/*初始化UART1,波特率为115200 */
void uart_init(void)
{
    /*初始化IO*/
    uart_io_init();
    /*初始化串口UART1*/
    uart_disable(UART1);
    uart_softreset(UART1);
    /*配置UART1*/
    UART1->UCR1=0;
    /*配置UART1的数据位、奇偶校验位、停止位等*/
    UART1->UCR2 = 0;
    UART1->UCR2 |= (1<<1)|(1<<2)|(1<<5)|(1<<14);  /*发送和接收使能*/
    UART1->UCR3 |= (1<<2);/*bit2必须为1*/
    /*设置波特率为:115200 */
    UART1->UFCR &= ~(7<<7); /*对RFDIV位域清零*/
    UART1->UFCR |= (5<<7);  /*1分频,uart_clock=80MHz*/
    UART1->UBIR=71;  //大坑,注意这里的UBIR,UBMR输入顺序不能变
    UART1->UBMR=3124;
    /*使能串口 */
    uart_enable(UART1);
}

/*关闭串口UART1*/
void uart_disable(UART_Type *base)
{
    base->UCR1 &= ~(1<<0);/*关闭指定的串口*/
}

/*关闭串口UART1*/
void uart_enable(UART_Type *base)
{
    base->UCR1 |= (1<<0);
}

/* 复位UART,软复位*/
void uart_softreset(UART_Type *base)
{
    base->UCR2 &= ~(1<<0);
    while( (base->UCR2 & 0x1)==0);
}

 /*UART1的IO初始化*/
 void uart_io_init(void)
 {
	IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX,0);  /*将引脚UART1_TX配置UART1_TX模式*/
    IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX,0);  /*将引脚UART1_RX配置UART1_RX模式*/
    IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10B0);/*配置UART1_TX电气属性*/
    IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX,0x10B0);/*配置UART1_RX电气属性*/
 }

/*通过UART1发送一个字符*/
void uart_putc(unsigned char c)
{
    while(((UART1->USR2>>3)& 0x01)==0);/*等于0说明数据一直在发送中*/
    UART1->UTXD=c;
}

/*通过UART1接收一个数据*/
unsigned char uart_getc(void)
{
    while(((UART1->USR2)& 0x01)==0);/*等待有数据可以读取*/
    return UART1->URXD;
}

/* 通过串口发送一串字符*/
void uart_puts(char *str)
{
    char *p =str;
    while(*p!='\0')
    {
        uart_putc(*p++);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloudAlibaba:4.2云原生网关higress的基本使用

概述 简介 Higress是基于阿里内部的Envoy Gateway实践沉淀、以开源Istio Envoy为核心构建的下一代云原生网关&#xff0c; 实现了流量网关 微服务网关 安全网关三合一的高集成能力&#xff0c;深度集成Dubbo、Nacos、Sentinel等微服务技术栈 定位 在虚拟化时期的微服务架构…

文本检测模型 DBNet 一种基于分割算法的模型 对每个像素点进行自适应二值化,并将二值化过程与网络训练相结合 可微分二值化模块 概率图

文本检测模型 DBNet DBNet文本检测模型是一种基于分割算法的模型,其优化之处在于对每个像素点进行自适应二值化,并将二值化过程与网络训练相结合。 传统的文本检测方法通常将二值化作为一个后处理步骤,与网络训练分开进行。而DBNet则提出了一种可微分的二值化方法,即将文…

类加载机制(双亲委派机制)

文章目录 JVM的作用是什么双亲委派机制加载流程 JVM的作用是什么 我们运行Java程序时&#xff0c;要安装JDK&#xff0c;JDK包含JVM&#xff0c;不同环境的JDK都是不同的。 Java 代码在编译后会形成 class 的字节码文件&#xff0c;该字节码文件通过 JVM 解释器&#xff0c;生…

【Linux】基于 Jenkins+shell 实现更新服务所需文件 -->两种方式:ssh/Ansible

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (四)

基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;四&#xff09; 大家继续看 https://lilianweng.github.io/posts/2023-06-23-agent/的文档内容 第三部分&#xff1a;工具使用 工具的使用是人类的一个显着而显着的特征。我们创造、修改和利用外部物体来完成超…

gocator导出图片

想用3D扫描后的图片&#xff0c;但是系统自带的导出方法很麻烦&#xff0c;所以考虑通过sdk导出 首先需要设置点云亮度 这里是导出图片的关键代码 case GoDataMessageType.SurfaceIntensity: { Debug.WriteLine("SurfaceIntensity "); GoSu…

C++ 中的 lambda 表达式

1.概念 lambda表达式实际上是一个匿名类的成员函数&#xff0c;该类由编译器为lambda创建&#xff0c;该函数被隐式地定义为内联。因此&#xff0c;调用lambda表达式相当于直接调用匿名类的operator()函数&#xff0c;这个函数可以被编译器内联优化&#xff08;建议&#xff0…

BGP第二篇(bgp邻居状态及影响邻居建立的因素)

1、bgp邻居状态 BGP对等体的交互过程中存在6种状态机&#xff1a; 空闲&#xff08;Idle&#xff09; 连接&#xff08;Connect&#xff09; 活跃 &#xff08;Active&#xff09; Open报文已发送&#xff08;OpenSent&#xff09; Open报文已确认&#xff08;OpenConfirm&…

Redis 源码安装和入门介绍

Linux下的redis源码安装 redis介绍 Redis 是一个开源&#xff08;BSD许可&#xff09;的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构&#xff0c;如 字符串&#xff08;strings&#xff09;&#xff0c;…

医疗图像处理2023年CVPR:Label-Free Liver Tumor Segmentation-无标签肝肿瘤分割

目录 一、摘要 二、介绍 三、相关工作 四、网络框架 1.位置选择 2.纹理处理 3.形状生成 4.后处理 5.参数设计 五、实验 1.数据集&#xff1a; 2.评价指标&#xff1a; 3.实现&#xff1a; 4.结果&#xff1a; 六、结论 一、摘要 通过在CT扫描中使用合成肿瘤&am…

秋招算法刷题10(栈和队列)

0509 232.用栈实现队列 class MyQueue {Deque<Integer> inStack;Deque<Integer> outStack;public MyQueue() {inStack new ArrayDeque<Integer>();outStack new ArrayDeque<Integer>();}public void push(int x) {inStack.push(x);}public int pop…

【计算机网络】计算机网络概述、计算机网络性能指标 习题1

0 1. 计算机网络可被理解为( )。 A.执行计算机数据处理的软件模块 B. 由自治的计算机互连起来的集合体 C.多个处理器通过共享内存实现的紧耦合系统 D. 用于共同完成一项任务的分布式系统 0 2.计算机网络最基本的功能是( )。 A.数据通信 B. 资源共享 C. 分布式处理 D. 信息综合…

关于一致性,你该知道的事儿(上)

关于一致性&#xff0c;你该知道的事儿&#xff08;上&#xff09; 前言一、缓存一致性二、内存模型一致性三、事务一致性四、分布式事务一致性4.1 分布式系统的一些挑战4.2 关于副本的一些概念4.3 分布式事务之共识问题4. 3.1 PC(two-phase commit, 2PC)4.3.2 Raft 三、后记参…

[240512] x-cmd 发布 v0.3.6: (se,wkp,ddgo...)x( kimi,gemini,gpt...)

目录 x-cmd 发布 v0.3.6新增了 jina 模块新增了 ddgo 模块新增了 se 模块wkp 模块新增了 writer 模块cosmo 模块 x-cmd 发布 v0.3.6 本次版本的最新引入的功能都是目的为了进一步探索 LLM 的使用。 本版本的改进分为两类&#xff1a;资讯类模块&#xff08;Wikipedia&#xf…

现代制造之Solidworks三维建模篇

现代制造 有现代技术支撑的制造业&#xff0c;即无论是制造还是服务行业&#xff0c;添了现代两个字不过是因为有了现代科学技术的支撑&#xff0c;如发达的通信方式&#xff0c;不断发展的互联网&#xff0c;信息化程度加强了&#xff0c;因此可以为这两个行业增加了不少优势…

【matlab基础知识代码】(十八)无约束最优化问题

min下面的x称为优化向量或者是决策变量 匿名函数法 >> f(x)(x(1)^2-2*x(1))*exp(-x(1)^2-x(2)^2-x(1)*x(2)); x0[0; 0]; [x,b,c,d]fminsearch(f,x0), x 0.6111 -0.3056 b -0.6414 c 1 d 包含以下字段的 struct: iterations: 72 funcCount: 137 algor…

【JavaEE 初阶(五)】文件操作和IO

❣博主主页: 33的博客❣ ▶️文章专栏分类:JavaEE◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多文件操作 目录 1.前言2.认识文件3.文件操作3.1File 属性3.2构造方法3.3File类方法 4.文件内容操作4.1R…

python内置类memoryview()详解

memoryview() Python 的一个内置class&#xff0c;可直接使用。它返回给定参数的“内存视图”对象。内存视图对象是一个对支持缓冲区协议&#xff08;如 bytes 或 bytearray&#xff09;的数据的“窗口”或“视图”&#xff0c;它允许你在不复制数据的情况下操作内存中的数据。…

【机器学习】 技术栈和开发环境搭建

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 博客目录 技术栈编程语言库框架编辑器项目IDE …

数据分析需要注意哪些法律法规

数据分析 前言一、数据处理过程二、数据收集阶段的法律规则数据收集应具备合法、正当、透明原则数据收集应坚持最小必要原则数据收集应遵守知情-同意规则数据收集应遵守目的明确性要求 三、数据储存的法律规则四、数据使用与处理的阶段的法律规则数据安全保护义务按照数据分级分…