第一部分、关于Timer定时器的储备知识
1、内部寄存器的个数
2、你要会的寄存器的使用方法
第二部分、新建Quartus II工程
1、注意
第三部分、修改别人软核
1、添加定时器IP核详细步骤
2、添加控制LED的PIOIP核步骤
3、复制生成的LED端口
第四部分、编写Quartus中的verilog代码
1、注意
第五部分、编写Ecplise里面的C代码
1、注意
2、C代码功能解析
3、代码
第六部分、总结
1、结果演示
2、闲话
3、完整资料
(1)status寄存器
//清除Timer中断标志寄存器
IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_BASE, 0);
(2)control寄存器
让control寄存器低四位为:0x0007(低四位0111),0——计数器开始(STOP = 0)计数器停止(STOP = 1);1——计数器开始运行(START = 1);1——设置为连续计数模式(CONT = 1)如果是0就是只计数一次;1——打开定时器中断(ITO = 1);
注意:这里我没有详细介绍NiosII定时器的寄存器的详细内容,自己去百度哦,或者私信找我要资料。
IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_1_BASE,0x0007);
(3)周期的高八位和第八位寄存器
明白计算方法:因为内部计数器是递减的,和51单片机是一样的。
所以你要延时1s时,那么1s除以1/100M = 1s *100M - 1 在到计算机中进行换算,再将高十六位赋值给PERIODH,低十六位赋值给PERIODL。(这里和51单片机的定时器中断特别像,只不过51单片机是高8位和低8位)
注意:不能超出定时器的位数,如果这里是32位的计数器(不信你自己去下面看定时器的配置,有个32),那么计数的最大值应该小于42.9s
100MHz表示频率是100M每秒,1/100M = 0.000 000 01s
所以 定时器中 2的32次方 = 4 294 967 296 * 0.000 000 01s =42.9s
2的64次方 = 184467440737 09 551 616 * 0.000 000 01 =5930.6年
//设置 PERIOD 寄存器
//PERIODH << 16 | PERIODL = 计数器周期因子 * 系统时钟频率因子 - 1
//PERIODH << 16 | PERIODL = 5s*100M - 1 = 499999999 = 0x1DCD_64FF
IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_1_BASE, 0x1DCD);//5s对应的高16位
OWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_1_BASE, 0x64FF); //5s对应的低16位
第一步、还是复制小梅哥的LCD9341的初始工程,到自己建立的文件夹中,为什么老是用这个工程?因为这个工程相当于一个基本的工程,如果你自己从零搭建,最终的结果还是和这个工程一样,那不如用别人搭建好的,我们会用就行。这个复制的详细步骤在(【NiosII学习】第一篇、如何烧录NiosII工程:https://blog.csdn.net/Learning1232/article/details/110225728)。
注意:如果你和我FPGA型号不一样,那就复制你的SOPC工程文件到文件夹中,和前面一样,因为其他的步骤大致都和我的一样,没有区别。
第一步、Timer定时器IP核的配置
第二步、进行连线,然后分配地址,然后再配置中断号,这里默认配置为3。
这里忘了回去看(第二篇),然后生成软核系统。
这里定时器没有生成可以例化的端口,但是需要例化控制LED的有四个端口,随后进行预编译。预编译完成后,分配四个LED的引脚,再全编译。
module AC620_GHRD(
//对端口进行定义
output wire [3:0] pio_led,
input wire clk, // clk.clk
input wire reset_n, // reset.reset_n
output wire lcd_rst, // lcd_rst.export
output wire lcd_rd_n, // lcd_rd.export
output wire lcd_bl, // lcd_bl.export
output wire lcd_wr_n, // lcd_wr.export
output wire lcd_rs, // lcd_rs.export
output wire lcd_cs_n, // lcd_cs.export
inout wire [15:0] lcd_data, // lcd_db.export
output wire sdram_clk, // sdram_clk.clk
output wire [11:0] sdram_addr, // sdram.addr
output wire [1:0] sdram_ba, // .ba
output wire sdram_cas_n, // .cas_n
output wire sdram_cke, // .cke
output wire sdram_cs_n, // .cs_n
inout wire [15:0] sdram_dq, // .dq
output wire [1:0] sdram_dqm, // .dqm
output wire sdram_ras_n, // .ras_n
output wire sdram_we_n, // .we_n
input wire uart_0_rxd, // uart_0.rxd
output wire uart_0_txd, // .txd
output wire epcs_dclk, // epcs.dclk
output wire epcs_sce, // .sce
output wire epcs_sdo, // .sdo
input wire epcs_data0 // .data0
);
mysystem u0 (
.clk_clk (clk), // clk.clk
.reset_reset_n (reset_n), // reset.reset_n
.uart_0_rxd (uart_0_rxd), // uart_0.rxd
.uart_0_txd (uart_0_txd), // .txd
.epcs_dclk (epcs_dclk), // epcs.dclk
.epcs_sce (epcs_sce), // .sce
.epcs_sdo (epcs_sdo), // .sdo
.epcs_data0 (epcs_data0), //
.lcd_rst_export (lcd_rst), // lcd_rst.export
.lcd_bl_export (lcd_bl), // lcd_bl.export
.lcd_wr_n (lcd_wr_n), // lcd.wr_n
.lcd_rd_n (lcd_rd_n), // .rd_n
.lcd_data (lcd_data), // .data
.lcd_rs (lcd_rs), // .rs
.lcd_cs_n (lcd_cs_n), //
.sdram_clk_clk (sdram_clk), // sdram_clk.clk
.altpll_0_phasedone_conduit_export (), // altpll_0_phasedone_conduit.export
.altpll_0_locked_conduit_export (), // altpll_0_locked_conduit.export
.altpll_0_areset_conduit_export (), // altpll_0_areset_conduit.export
.sdram_addr (sdram_addr), // sdram.addr
.sdram_ba (sdram_ba), // .ba
.sdram_cas_n (sdram_cas_n), // .cas_n
.sdram_cke (sdram_cke), // .cke
.sdram_cs_n (sdram_cs_n), // .cs_n
.sdram_dq (sdram_dq), // .dq
.sdram_dqm (sdram_dqm), // .dqm
.sdram_ras_n (sdram_ras_n), // .ras_n
.sdram_we_n (sdram_we_n), // .we_n
//复制过来的端口
.pio_led_export (pio_led) // pio_led.export
);
endmodule
这里省略了Ecplise软件的使用说明,如果忘了的小伙伴,可以看我的《【NiosII学习】第一篇、如何烧录NiosII工程:https://blog.csdn.net/Learning1232/article/details/110225728》,有详细的步骤。注意:你还能忘,那你真该打。
四个LED亮5秒又灭五秒,如此循环
/*
* main.c
*
* Created on: 2020年12月13日
* Author: dpt
*
*/
#include "system.h" //系统头文件
#include "altera_avalon_timer_regs.h" //定时器头文件
#include "altera_avalon_pio_regs.h" //PIO 头文件
#include "sys/alt_irq.h" //中断头文件
#include "unistd.h" //延迟函数头文件
#include //标准的输入输出头文件
#include "priv/alt_legacy_irq.h"
alt_u32 i=0;
alt_u32 timer_isr_context; //定义全局变量以储存 isr_context 指针
void Timer_Initial(void); //定时器中断初始化
void Timer_ISR_Interrupt(void); //定时器中断服务子程序
//--------------------------------------------------------------------------- //-- 名称 : Timer_Initial()
//-- 功能 : 定时器中断初始化
//-- 输入参数 : 无
//-- 输出参数 : 无§4 Qsys 丰富多彩的内置 IP 核 161
//---------------------------------------------------------------------------
void Timer_Initial(void)
{
//改写 timer_isr_context 指针以匹配 alt_irq_register()函数原型
void* isr_context_ptr = (void*) &timer_isr_context;
//设置 PERIOD 寄存器
//PERIODH << 16 | PERIODL = 计数器周期因子 * 系统时钟频率因子 - 1
//PERIODH << 16 | PERIODL = 5s*100M - 1 = 499999999 = 0x1DCD_64FF
IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_1_BASE, 0x1DCD);
IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_1_BASE, 0x64FF);
//设置 CONTROL 寄存器
//位数 | 3 | 2 | 1 | 0 |
//CONTROL | STOP | START | CONT | ITO |
//ITO 1,产生 IRO; 0,不产生 IRQ
//CONT 1,计数器连续运行直到 STOP 被置一; 0,计数到 0 停止
//START 1,计数器开始运行; 0,无影响
//STOP 1,计数器停止运行; 0,无影响
IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_1_BASE,
ALTERA_AVALON_TIMER_CONTROL_START_MSK | //START = 1
ALTERA_AVALON_TIMER_CONTROL_CONT_MSK | //CONT = 1
ALTERA_AVALON_TIMER_CONTROL_ITO_MSK); //ITO = 1
//注册Timer1中断
alt_irq_register(TIMER_1_IRQ, NULL, Timer_ISR_Interrupt);
}
//---------------------------------------------------------------------------
//-- 名称 : Timer_Initial()
//-- 功能 : 定时器中断服务子程序
//-- 输入参数 : timer_isr_context,用于传递中断状态寄存器的值,id,中断号
//-- 输出参数 : 无
//---------------------------------------------------------------------------
void Timer_ISR_Interrupt(void)
{
//用户中断代码
i = 1;
//应答中断,将 STATUS 寄存器清零
IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_1_BASE,~ALTERA_AVALON_TIMER_STATUS_TO_MSK);
}
//---------------------------------------------------------------------------
//-- 名称 : main()
//-- 功能 : 程序入口
//-- 输入参数 : 无
//-- 输出参数 : 无
//---------------------------------------------------------------------------
int main(void)
{
alt_u32 led_state = 0xff; //初始化 Led
Timer_Initial(); //初始化定时器中断
printf("Welcome To Timer Ip Demo Program... \n");
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, 0x00); //首先让四个灯全亮
while(1)
{
if(i == 1)
{
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, led_state);//使 led 全灭
led_state = ~led_state;
i = 0;
}
}
}
我已经拍成视频放在群文件中,你也可以先点击这个链接直接观看(https://live.csdn.net/v/120133),这里放张图片。
这篇笔记所设计到的所有的资料我都会放到下面这个群的群文件中,欢迎老铁扫码进QQ群一起学习。博主也还是笨学生,我要是不会可别喷我哈。当然还有第二种方法,关注我,就可以直接下载了!
欢乐的白嫖时光从来不会缺席,向白嫖致敬!(完整工程、演示视频、参考资料下载链接:https://download.csdn.net/download/Learning1232/13680002)