红圈1处是用于预设硬件生成后的定时器周期, 也就是说这是个初始值,我们可以通过软件来改变定时器的周期。红圈2处是定时器计数器的大小,它分为32位和64位两种,需要根据你的定时器的周期来选择,我们在这里选择32位。红圈3处是定时器的几种预设方式,是为了实现不同的功能,我们在这里选择Full-featured,就是全功能。选择了这个选项,我们就可以修改周期,可以控制停止开始位。选择好以后,点击Finish完成设置。
system.h
/*
* timer1 configuration
*
*/
#define TIMER1_NAME "/dev/timer1"
#define TIMER1_TYPE "altera_avalon_timer"
#define TIMER1_BASE 0x00001820
#define TIMER1_SPAN 32
#define TIMER1_IRQ 4
#define TIMER1_IRQ_INTERRUPT_CONTROLLER_ID 0
#define TIMER1_ALWAYS_RUN 0
#define TIMER1_FIXED_PERIOD 0
#define TIMER1_SNAPSHOT 1
#define TIMER1_PERIOD 500
#define TIMER1_PERIOD_UNITS "ms"
#define TIMER1_RESET_OUTPUT 0
#define TIMER1_TIMEOUT_PULSE_OUTPUT 0
#define TIMER1_LOAD_VALUE 49999999
#define TIMER1_COUNTER_SIZE 32
#define TIMER1_MULT 0.0010
#define TIMER1_TICKS_PER_SEC 2
#define TIMER1_FREQ 100000000
#define ALT_MODULE_CLASS_timer1 altera_avalon_timer
/*
* timer2 configuration
*
*/
#define TIMER2_NAME "/dev/timer2"
#define TIMER2_TYPE "altera_avalon_timer"
#define TIMER2_BASE 0x00001840
#define TIMER2_SPAN 32
#define TIMER2_IRQ 5
#define TIMER2_IRQ_INTERRUPT_CONTROLLER_ID 0
#define TIMER2_ALWAYS_RUN 0
#define TIMER2_FIXED_PERIOD 0
#define TIMER2_SNAPSHOT 1
#define TIMER2_PERIOD 1
#define TIMER2_PERIOD_UNITS "ms"
#define TIMER2_RESET_OUTPUT 0
#define TIMER2_TIMEOUT_PULSE_OUTPUT 0
#define TIMER2_LOAD_VALUE 99999
#define TIMER2_COUNTER_SIZE 32
#define TIMER2_MULT 0.0010
#define TIMER2_TICKS_PER_SEC 1000
#define TIMER2_FREQ 100000000
#define ALT_MODULE_CLASS_timer2 altera_avalon_timer
大家在开发NIOS软件的时候,要注意一定要先看systetm.h文件,首先确定硬件已经正确加载,而且名字跟你设定的是一样的,避免在这个地方出现问题。
main.c
/*-----------------------------------------------------------------------------
* Include
*-----------------------------------------------------------------------------*/
#include <stdio.h>
#include <sys/unistd.h>
#include <io.h>
#include <string.h>
#include "system.h"
#include "altera_avalon_pio_regs.h"
#include "altera_avalon_timer_regs.h"
#include "alt_types.h"
#include "sys/alt_irq.h"
#include "../inc/sopc.h"
/*-----------------------------------------------------------------------------
* Variable
*-----------------------------------------------------------------------------*/
static void timer_init(void); //初始化中断
int i = 0,j = 0,flag;
alt_u32 timer_prd[4] = {5000000, 10000000, 50000000, 100000000};//定时器的周期
//定时器的定时时间的计算方法是:定时器的时钟数/定时器的时钟周期,我用的系统时钟是100MHz,所以,上面的四个的定时时间就为{0.05, 0.1, 0.5, 1}
/*
* === FUNCTION ======================================================================
* Name: main
* Description:
* =====================================================================================
*/
int main(void)
{
//初始化Timer
timer_init();
while(1);
return 0;
}
/*
* === FUNCTION ======================================================================
* Name: ISR_timer
* Description:
* =====================================================================================
*/
static void ISR_timer1(void *context, alt_u32 id)
{
//控制流水灯闪烁,一共四个LED
LED->DATA = 1<<i;
i++;
if(i == 4)
i = 0;
//清除Timer中断标志寄存器
IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER1_BASE, 0x00);
}
/*
* === FUNCTION ======================================================================
* Name: ISR_timer2
* Description: 通过定时器2来改变定时器1的周期,改变后需要重新启动定时器
* =====================================================================================
*/
static void ISR_timer2(void *context, alt_u32 id)
{
//改变定时器1的周期
IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER1_BASE, timer_prd[j]);
IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER1_BASE, timer_prd[j] >> 16);
//重新启动定时器
IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER1_BASE, 0x07);
//闪烁频率先高后低然后又变高
if(j == 0)
flag = 0;
if(j == 3)
flag = 1;
if(flag == 0){
j++;
}
else{
j--;
}
//清除中断标志位
IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER2_BASE, 0);
}
/*
* === FUNCTION ======================================================================
* Name: timer_init
* Description:
* =====================================================================================
*/
void timer_init(void) //初始化中断
{
//清除Timer1中断标志寄存器
IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER1_BASE, 0x00);
//设置Timer1周期
IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER1_BASE,80000000);
IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER1_BASE, 80000000 >> 16);
//允许Timer1中断
IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER1_BASE, 0x07);
//注册Timer1中断
alt_irq_register(TIMER1_IRQ, (void *)TIMER1_BASE, ISR_timer1);
//清除Timer2中断标志寄存器
IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER2_BASE, 0x00);
//设置Timer2周期
IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER2_BASE,400000000);
IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER2_BASE, 400000000 >> 16);
//允许Timer2中断
IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER2_BASE, 0x07);
//注册Timer2中断
alt_irq_register(TIMER2_IRQ, (void *)TIMER2_BASE, ISR_timer2);
}
上面的方式是通过HAL提供的API实现的,当然我们也可以通过我以前提供的方法实现,建立一个结构体,直接对寄存器进行赋值,这样的方法我更喜欢,清晰而且结构完全自己控制。下面提供给大家一个这个结构体,实现方法大家自己实现吧,很简单,一句一句替换就可以了。建立结构体的内容根据下面的表格决定。
04 |
volatile unsigned long int TO :1; |
05 |
volatile unsigned long int RUN :1; |
06 |
volatile unsigned long int NC :30; |
08 |
volatile unsigned long int WORD ; |
13 |
volatile unsigned long int ITO :1; |
14 |
volatile unsigned long int CONT :1; |
15 |
volatile unsigned long int START:1; |
16 |
volatile unsigned long int STOP :1; |
17 |
volatile unsigned long int NC :28; |
19 |
volatile unsigned long int WORD ; |
22 |
volatile unsigned long int PERIODL; |
23 |
volatile unsigned long int PERIODH; |
24 |
volatile unsigned long int SNAPL; |
25 |
volatile unsigned long int SNAPH; |
有了这个结构体就可以按照我之前给大家讲的方法实现定时器功能了。到此,我说的定时器的方法就讲完了,同时用两个定时器的问题也能够得以解决了。
下面,我给大家一个有关定时器系统时钟的例程作为参考,但我不建议大家使用,原因我已经说过了。这个函数实现的是每隔一秒点亮一个LED,一共4个LED。首先需要软件设置一下,如下图所示,进入系统库属性,在System clock timer选项框中选择你要的定时器。选择好以后,需要重新编译才行。
20 |
#include "altera_avalon_pio_regs.h" |
21 |
#include "alt_types.h" |
22 |
#include "sys/alt_irq.h" |
23 |
#include "../inc/sopc.h" |
24 |
#include "sys/alt_alarm.h" |
29 |
alt_u32 my_alarm_callback( void *context); |
35 |
unsigned int alarm_flag; |
40 |
#define INTEVAL_TICK 1 |
54 |
if (alt_alarm_start(&alarm,INTEVAL_TICK,my_alarm_callback,NULL) < 0){ |
56 |
printf ( "Error: No system clock available\n" ); |
62 |
printf ( "Success: System clock available\n" ); |
87 |
alt_u32 my_alarm_callback( void *context) |