0%

ZYNQ嵌入式之定时器(基于PYNQ-Z2开发板)

本节主要通过定时器中断控制LED亮灭来简单演示定时器的使用

定时器的基本概念

  • 每个Cortex-A9处理器都有一个私有的32位定时器(提供常规的记时记数以及输出PWM)和一个32位的看门狗定时器(实现监控和监视,当系统发生灾难性故障的时候,让程序能重启,恢复正常状态)
  • 每个处理器都共享一个64位的定时器
  • 这些定时器的频率总是CPU频率的一半
  • 在系统层面来说,还有一个24位的看门狗定时器和两个三重定时器(对信号的脉冲宽度进行计数)

定时器中断实验

  • 实验任务:通过定时器的中断,每1s控制一次PL LED灯的亮灭

1.Vivado中的配置

  • 与配置EMIO实验一样

2.Vitis中的代码编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include<iostream>
#include<xparameters.h>
#include<xgpiops.h>
#include<xscutimer.h>
#include<xscugic.h>

using namespace std;

/***********************参数声明**********************/
/*GPIO相关参数*/
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define EMIO54_LED0 54 //PL端的第54个pin分配给LED0
XGpioPs Gpio; //GPIO设备的驱动程序实例

/*定时器相关参数*/
#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID //定时器器件ID
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR //定时器中断ID
#define TIMER_LOAD_VALUE 0x135EFB82 //定时器的装载值
/*想要延时1s: 时钟为1/2的CPU时钟,即为650/2=325MHz。
先计算时钟周期:1s/325M=3.077ns
1s对应数字:1s/3.077ns =0x135EFB83 (因为从0开始计数,则在0x135EFB83的结果上-1,即为0x135EFB82) */
XScuTimer TimerInstance; //Cortex A9私有定时器的实例

/*中断相关参数*/
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID //中断控制器的ID
XScuGic IntcInstance; //中断控制器的实例

/***********************函数声明**********************/
void gpio_init(void);
void timer_init(XScuTimer *TimerInstancePtr,u16 TimerDeviceId);
void timer_intr_init(XScuGic *IntcInstancePtr,XScuTimer *TimerInstancePtr,u16 TimerIntrId);
void timer_intr_handler(void *CallBackRef);

/***********************主函数入口**********************/
int main(void)
{
gpio_init();
timer_init(&TimerInstance, TIMER_DEVICE_ID);
timer_intr_init(&IntcInstance, &TimerInstance, TIMER_IRPT_INTR);
XScuTimer_Start(&TimerInstance);//开启定时器
while(1);
return 0;
}

void gpio_init(void)
{
XGpioPs_Config * ConfigPtr;

//配置器件的ID,查找器件的配置信息
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//初始化GPIO驱动
XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);

//设置GPIO的方向(0:输入/1:输出)
XGpioPs_SetDirectionPin(&Gpio,EMIO54_LED0, 1);

//设置输出使能(1:关闭/1:打开)
XGpioPs_SetOutputEnablePin(&Gpio, EMIO54_LED0, 1);

//XGpioPs_WritePin(&Gpio, EMIO54_LED0, led_value);
}

//定时器初始化
void timer_init(XScuTimer *TimerInstancePtr,u16 TimerDeviceId)
{
XScuTimer_Config *ConfigPtr;

//初始化私有定时器
ConfigPtr = XScuTimer_LookupConfig(TimerDeviceId);
XScuTimer_CfgInitialize(TimerInstancePtr, ConfigPtr, ConfigPtr->BaseAddr);

//配置计数器初始值
XScuTimer_LoadTimer(TimerInstancePtr, TIMER_LOAD_VALUE);

//使能自动装载模式
XScuTimer_EnableAutoReload(TimerInstancePtr);
}

//定时器中断初始化
void timer_intr_init(XScuGic *IntcInstancePtr,XScuTimer *TimerInstancePtr,u16 TimerIntrId)
{
XScuGic_Config *IntcConfig;

IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);

//中断异常处理
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
IntcInstancePtr);
Xil_ExceptionEnable();

//设置定时器的中断处理函数
XScuGic_Connect(IntcInstancePtr, TimerIntrId,
(Xil_ExceptionHandler)timer_intr_handler,
(void *)TimerInstancePtr);

//使能中断控制器
XScuGic_Enable(IntcInstancePtr, TimerIntrId);

//使能定时器中断
XScuTimer_EnableInterrupt(TimerInstancePtr);

}

//定时器中断处理函数
void timer_intr_handler(void *CallBackRef)
{
static int led_status = 1;
XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
//进入中断之后清除中断
if(XScuTimer_IsExpired(TimerInstancePtr))
{
//向MIO引脚写入高低电平,只看最低位是0还是1
XScuTimer_ClearInterruptStatus(TimerInstancePtr); //每次进入中断后清除中断
XGpioPs_WritePin(&Gpio, EMIO54_LED0, led_status);
led_status = ~led_status;
}

}
欢迎来到ssy的世界