网站导航栏高度,做网站要花钱吗,今天宁波最新消息,网站关键词布局目录 1. 定时器配置流程1.1 EPIT定时器简介1.2 定时器1(epit1)的配置流程1.3 配置代码(寄存器版本)1.4 定时器-配合按键消抖1.4.1 实现原理1.4.2 代码实现#xff08;寄存器版#xff09; 2. GPT定时器实现高精度延时2.1 延时原理分析2.2 代码实现 3. UART串口配置流程3.1 UA… 目录 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)的配置流程 初始化定时器设计定时器相应的寄存器配置例如时钟源、分频系数、计数重装值、计数初值等使能定时器这个对于很多外设都是如此如歌配置好了初始化基本都要进行使能进行工作使能GIC中断服务控制器开启中断对中断服务函数进行注册:中断注册函数的内容可以具体里哦阿姐在IMX6ULL的中断服务系统编写中断服务函数的内容这个的注意事项就是完成中断任务后要进行中断标志位的清除
1.3 配置代码(寄存器版本)
/*初始化EPIT定时器函数*/
void epit1_init(unsigned int frac,unsigned int lodvalue)
{if(frac4095){frac 4095;}/*配置控制寄存器CR*/EPIT1-CR 0;/*清零*/EPIT1-CR (11)|(12)|(13)|(frac4)|(124);EPIT1-LR lodvalue;/*加载寄存器的值相当于到计数值*/EPIT1-CMPR 0;/*计数器从lodvalue计数到0的话就触发中断*//*初始化中断使能中中断*/GIC_EnableIRQ(EPIT1_IRQn);system_register_irqhandler(EPIT1_IRQn,epit1_irqhandler,NULL);/*中断ID中断服务函数给中断服务函数传递的参数*//*打开EPIT定时器*/EPIT1-CR |(10);
}
/*中断服务函数的编写*/void epit1_irqhandler(unsigned int gicciar,void *param){static unsigned char state 0;state !state;if(EPIT1-SR(10))//判断最后一位是不是0如果为真表示中断发生{led_switch(LED0,state);/*反转LED0灯*/}/*清除标志位*/EPIT1-SR1;/*写清零中断标志位*/}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.directionkGPIO_DigitalInput;key_config.interruptModekGPIO_IntFallingEdge; //注意这里错误//错误设置成低电平触发导致按键按下去频繁进入中断//key_config.interruptModekGPIO_IntLowLevelkey_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 (11)|(12)|(13)|(124);/*不分频*/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 ~(10);
}
/*重启EPIT1定时器*/
void filtertimer_restart(unsigned int value)
{EPIT1-CR ~(10);//先关闭EPIT1-LR value; //装载值EPIT1-CR | (10);//再打开
}
/*注册EPIT1定时器中断处理函数*/
void filtertimer_irqhandler(unsigned int gicciar,void *param)
{static unsigned char state 0;if(EPIT1-SR (10)){/*关闭定时器*/filtertimer_stop();if(gpio_pinread(GPIO1,18)0){state ! state;beep_switch(state);}}EPIT1-SR | 10; /*写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 TimerGPT是一个32位的向上计数器是通用的定时器同时具备一个12位的分频器不是只能进行12分频他的基本特性如下所示
一个可选时钟源的 32 位向上计数器。两个输入捕获通道可以设置触发方式。三个输出比较通道可以设置输出模式。可以生成捕获中断、比较中断和溢出中断。计数器可以运行在重新启动(restart)或(自由运行)free-run 模式。但是一般就是用作重装载模式
2.1 延时原理分析 本质上还是利用定时器计数的原理只不过这里的计时是进行增量计时法。例如对于GPT定时器而言其时钟源是66MHz的对齐进行66分频后就是1Mhz,也就是计数器寄存器CNT计数一次时间就过去了1us因此我们可以可以让中国CNT计数器一直进行计数每次进入到延时函数就把这次的CNT记录下来例如此时是100然后我们要延时200那么我们要做的就是等到CNT300时我们再出延时函数这样就实现了延时的效果但是可能会出现溢出的情况因此我们要再延时函数中对溢出情况i进行处理具体的实现如下注意在进入延时函数前定时器就是一直再走因此进入延时函数时定时器也在走并且运行延时的每行代码定时器都走因此这里的计时是增量计时法
2.2 代码实现 3. UART串口配置流程
3.1 UART串口通信基本概念
3.1.1 基本术语
串行就是数据一位一位的顺序传递异步通信比如A和B通信那么异步通信就是两边都要设置时钟且保持一致如果保持不一致就可能会发生数据传输失败同步通信顾名思义就是通信设备A和B是共用一条时钟线路保持同步半双工可以这样理解工作一半也就是发送数据和接受数据只能一时进行一个也就是同一时间只能发数据或者收数据全双工这个与半双工是相反的即同一时间发送和接收数据是通一时间进行的
我们明白上面的概念后就可以对串口通信UART进行一个定义串口通信就是串行异步全双工的通信方式
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 ^ 11 ^ 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-UCR10;/*配置UART1的数据位、奇偶校验位、停止位等*/UART1-UCR2 0;UART1-UCR2 | (11)|(12)|(15)|(114); /*发送和接收使能*/UART1-UCR3 | (12);/*bit2必须为1*//*设置波特率为115200 */UART1-UFCR ~(77); /*对RFDIV位域清零*/UART1-UFCR | (57); /*1分频uart_clock80MHz*/UART1-UBIR71; //大坑注意这里的UBIRUBMR输入顺序不能变UART1-UBMR3124;/*使能串口 */uart_enable(UART1);
}/*关闭串口UART1*/
void uart_disable(UART_Type *base)
{base-UCR1 ~(10);/*关闭指定的串口*/
}/*关闭串口UART1*/
void uart_enable(UART_Type *base)
{base-UCR1 | (10);
}/* 复位UART软复位*/
void uart_softreset(UART_Type *base)
{base-UCR2 ~(10);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-USR23) 0x01)0);/*等于0说明数据一直在发送中*/UART1-UTXDc;
}/*通过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);}
}