本实验的源码工程在开发板光盘资料的:i.MX6UL终结者光盘资料\04_裸机例程源码\11_gpt_delay 目录下。我们在Ubuntu系统下使用命令“mkdir 11_gpt_delay”建立“11_gpt_delay”文件夹,如图 1所示:
然后使用“cd 11_gpt_delay”命令进入到11_gpt_delay文件夹,如图 2所示:
然后使用命令“cp -r …/10_key_filter/* ./”将上一章试验中的所有内容拷贝到刚刚新建的“11_gpt_delay”里面,如图 3所示:
然后我们只需要修改“drivers/delay”目录下的delay.h和delay.c,两个文件,首先我们打开“drivers/delay/delay.h”文件,在里面输入下面的内容:
1 #ifndef __BSP_DELAY_H
2 #define __BSP_DELAY_H
3
4 #include "imx6ul.h"
5
6
7 /* 函数声明 */
8 void delay_init(void);
9 void delayus(unsigned int usdelay);
10 void delayms(unsigned int msdelay);
11 void delay(volatile unsigned int n);
12 void gpt1_irqhandler(void);
13
14 #endif
我们可以看到在delay.h里面主要添加了几个函数的声明,然后我们打开“deivers/delay/delay.c”文件,在里面输入下面的内容:
1 #include "delay.h"
2
3 /*
4 * @description : 延时有关硬件初始化,主要是GPT定时器
5 GPT定时器时钟源选择ipg_clk=66Mhz
6 * @param : 无
7 * @return : 无
8 */
9 void delay_init(void)
10 {
11 GPT1->CR = 0; /* 清零,bit0也为0,即停止GPT */
12
13 GPT1->CR = 1 << 15; /* bit15置1进入软复位 */
14 while((GPT1->CR>>15)&0x01);/* 等待复位完成 */
15
16 /*
17 * GPT的CR寄存器,GPT通用设置
18 * bit22:20 000 输出比较1的输出功能关闭,也就是对应的引脚没反应
19 * bit9: 0 Restart模式,当CNT等于OCR1的时候就产生中断
20 * bit8:6 001 GPT时钟源选择ipg_clk=66Mhz
21 * bit
22 */
23 GPT1->CR = (1<<6);
24
25 /*
26 * GPT的PR寄存器,GPT的分频设置
27 * bit11:0 设置分频值,设置为0表示1分频,
28 * 以此类推,最大可以设置为0XFFF,也就是最大4096分频
29 */
30 GPT1->PR = 65; /* 设置为65,GPT1时钟为66M/(65+1)=1MHz */
31
32 /*
33 * GPT的OCR1寄存器,GPT的输出比较1比较计数值,
34 * GPT的时钟为1Mz,那么计数器每计一个值就是就是1us。
35 * 为了实现较大的计数,我们将比较值设置为最大的0XFFFFFFFF,
36 * 这样一次计满就是:0XFFFFFFFFus = 4294967296us = 4295s = 71.5min
37 * 也就是说一次计满最多71.5分钟,存在溢出
38 */
39 GPT1->OCR[0] = 0XFFFFFFFF;
40
41 GPT1->CR |= 1<<0; //使能GPT1
42
43 /* 一下屏蔽的代码是GPT定时器中断代码,
44 * 如果想学习GPT定时器的话可以参考一下代码。
45 */
46 }
47
48 /*
49 * @description : 微秒(us)级延时
50 * @param - value : 需要延时的us数,最大延时0XFFFFFFFFus
51 * @return : 无
52 */
53 void delayus(unsigned int usdelay)
54 {
55 unsigned long oldcnt,newcnt;
56 unsigned long tcntvalue = 0; /* 走过的总时间 */
57
58 oldcnt = GPT1->CNT;
59 while(1)
60 {
61 newcnt = GPT1->CNT;
62 if(newcnt != oldcnt)
63 {
64 if(newcnt > oldcnt) /* GPT是向上计数器,并且没有溢出 */
65 tcntvalue += newcnt - oldcnt;
66 else /* 发生溢出 */
67 tcntvalue += 0XFFFFFFFF-oldcnt + newcnt;
68 oldcnt = newcnt;
69 if(tcntvalue >= usdelay)/* 延时时间到了 */
70 break; /* 跳出 */
71 }
72 }
73 }
74
75 /*
76 * @description : 毫秒(ms)级延时
77 * @param - msdelay : 需要延时的ms数
78 * @return : 无
79 */
80 void delayms(unsigned int msdelay)
81 {
82 int i = 0;
83 for(i=0; i<msdelay; i++)
84 {
85 delayus(1000);
86 }
87 }
88
89 /*
90 * @description : 短时间延时函数
91 * @param - n : 要延时循环次数(空操作循环次数,模式延时)
92 * @return : 无
93 */
94 void delay_short(volatile unsigned int n)
95 {
96 while(n--){
}
97 }
98
99 /*
100 * @description : 延时函数,在396Mhz的主频下
101 * 延时时间大约为1ms
102 * @param - n : 要延时的ms数
103 * @return : 无
104 */
105 void delay(volatile unsigned int n)
106 {
107 while(n--)
108 {
109 delay_short(0x7ff);
110 }
111 }
我们在delay.c文件里面增加了三个函数:delay_init、delayus、delayms。
delay_init函数是延时初始化函数,主要完成了初始化GPT1定时器,设置时钟源,分频值和比较寄存器,最后使能GPT1定时器。
delayus函数是微秒级的延时,传入的参数代表要延时的微秒。在这个函数中我们对计数器溢出的情况作了处理。
delayms函数是毫秒级延时,传入的参数代表要延时的毫秒。
然后我们打开main.c文件,输入下面的内容:
1 #include "clk.h"
2 #include "delay.h"
3 #include "led.h"
4 #include "beep.h"
5 #include "key.h"
6 #include "int.h"
7 #include "keyfilter.h"
8
9 /*
10 * @description : main函数
11 * @param : 无
12 * @return : 无
13 */
14 int main(void)
15 {
16 unsigned char state = OFF;
17
18 int_init(); /* 初始化中断(一定要最先调用!) */
19 imx6u_clkinit(); /* 初始化系统时钟 */
20 delay_init(); /* 初始化延时 */
21 clk_enable(); /* 使能所有的时钟 */
22 led_init(); /* 初始化led */
23 beep_init(); /* 初始化beep */
24
25 while(1)
26 {
27 state = !state;
28 led_switch(LED0, state);
29 delayms(500);
30 }
31
32 return 0;
33 }
我们在main.c文件中调用delay_init延时初始化函数,最后在while(1)循环中调用delayms毫秒延时函数,每隔500毫秒切换led的状态。