NIOS II 常见错误:
1.这个错误是由什么引起?提示LED_ PIO_BASE没有声明
答:这是因为名字不一致引起的比如,在生成SOPC系统时,双击PIO(Parallel I/O)(在Avalon Modules -> Other 下),为系统添加输出接口,你没有把该组件改名成LED_PIO,而是保留了原始的名字:PIO_0;但你又通过 IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, led);来向该组件写入数据,就会导致上述错误。解决办法:1.可以修改sopc系统,为该PIO改名为LED_PIO ;2.在hello_led.c的前面给LED_PIO_BASE赋值,如#define LED_PIO_BASE 0x00001800,后面的这个地址要与SOPC中的地址对应.
2. 怎样在NIOSII中操作PIO,提供一种参考方法。
答:hello_led.c是这样写IO口的: IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, led); 首先在altera_avalon_pio_regs.h找到定义 #i nclude<IO.H> #define IORD_ALTERA_AVALON_PIO_DATA(base) IORD(base, 0) #define IOWR_ALTERA_AVALON_PIO_DATA(base, data) IOWR(base, 0, data) 因此在NIOSII中可以调用#i nclude<IO.H>库函数IORD/IOWR来操作PIO。 在smallsoftwarehello_led_0_syslibDebugsystem_des cription下的system.h 中,有以下内容: #define LED_PIO_TYPE "altera_avalon_pio" #define LED_PIO_BASE 0x00004000 其中LED_PIO_BASE(IO寄存器地址?)为0x00004000同SOPCBuilder中设置一致! (其实在SopcBuilder中有关NiosII的配置,就是通过system.h来传送给IDE的!) 最后用IOWR(0x00004000, 0, led);替代 IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, led);编译,下载到开发板上,运行成功!
3.出错信息如下:
Linking hello_world_0.elf... /cygdrive/e/DE2Project_restored/software/hello_world_0_syslib/Debug/libhello_world_0_syslib.a(alt_main.o)(.text+0x60): In function `alt_main': /cygdrive/c/altera/72/nios2eds/components/altera_hal/HAL/src/alt_main.c:163: undefined reference to `main' collect2: ld returned 1 exit status make: *** [hello_world_0.elf] Error 1 Build completed in 1.953 seconds 答:将主函数名字写错了.
应该写成int main(void),结果写成了 int mian()
悲剧!!!!!!
4.IOWR_ALTERA_AVALON_PIO_DATA怎么使用?
答:IOWR_ALTERA_AVALON_PIO_DATA是一个宏定义,其位置在altera_avalon_pio_regs.h中,另外还要参考io.h头文件。NiosII IDE为了避开NiosII的Cache以及简化IO端口操作程序的编写,定义了两类基本的宏(以IOWR_开头的为写PIO操作,以IORD_开头的为读PIO操作),其效果与使用指针的效果不完全一样。 LED_PIO_BASE是在system.h中定义的一个宏,是LED_PIO端口的基地址。 IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE,led)的含义就是往LED_PIO端口的数据输出寄存器写入led, 具体可以参考 Altera_embeded_peripherals 一文,这里讲解了一个PIO端口包含了那些寄存器。参考NiosII_software_developer's_handbook 进行驱动设计。这两个文件可以在Altera的官方网站上下载。 |
NIOS_II 学习笔记: 在这里先简单介绍一下各头文件的作用,,<stdio.h>这个头文件包含了标准输入、输出、错误函数库;"system.h",这个文件描述了每个设备并给出了以下一些详细信息:设备 的硬件配置、基地址、中断优先级、设备的符号名称,用户不需要编辑system.h 文件,此文件由HAL 系统库自动生成,其内容取决于硬件配置和用户在IDE 中设置的系统库属性;“altera_avalon_pio_regs.h ” 这个文件是通用I/O 口与高层软件之间的接口.IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, led)这个函数就是在此文件中定义的,此函数的功能为将数值(led)赋给LED_PIO_BASE 为基地址的用户自定义的I/O 口上,也就是将led 这个值赋给我们硬件中LED 灯所接的FPGA 管脚上;“alt_types.h”头文件定义了数据类型,如下表所示
类型 说明 alt_8 有符号8 位整数 alt_u8 无符号8 位整数 alt_16 有符号16 位整数 alt_u16 无符号16 位整数 alt_32 有符号32 位整数
alt_u32 无符号32 位整数
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE,0xf); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE,0x0); IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE); alt_irq_register(BUTTON_PIO_IRQ,edge_capture_ptr,handle_button_interrupts) 在文件"altera_avalon_pio_regs.h"中有如下定义 #define IOWR_ALTERA_AVALON_PIO_IRQ_MASK(base,data)IOWR(base,2,data) #define IOWR_ALTERA_AVALON_PIO_EDGE_CAP(base,data)IOWR(base,3,data) #define IORD_ALTERA_AVALON_PIO_EDGE_CAP(base)IORD(base,3) 第一个函数是使能中断函数,是按位来势能的,比如0xf表示四位全部使能,而0x7表示使能 低3位中断;
第二个函数是设置边沿捕获寄存器函数,用来重新设定寄存器的值;一般在读取之后会重新设 定为0;
第三个函数是读取边沿捕获寄存器函数,用来读取寄存器的值; 下面是alt_irq_register函数的原形,此函数用来声明ISR,在软使用IRS之前一定要先声明; extern int alt_irq_register(alt_u32 id, void*context, void(*irq_handler)(void*,alt_u32)); 一般在开发按键中断程序时,handle_button_interrupts()和init_button_pio()这两个函 数直接使用,不用再编辑。
|
系统配置文件如下: 1.流水灯
#include "system.h" #include "altera_avalon_pio_regs.h" #include "alt_types.h" #include "stdio.h" #include "unistd.h" int main (void) __attribute__ ((weak, alias ("alt_main"))); int alt_main (void) { unsigned char led = 0;
while (1) { for(led=0;led<8;led++) { IOWR_ALTERA_AVALON_PIO_DATA(LED_GREEN_BASE, 1<<led); usleep(500000); //延时0.5秒 } } return 0; }
|
2.流水灯
count_binary.h文件
#ifndef COUNT_BINARY_H_ #define COUNT_BINARY_H_ #include "alt_types.h" #include <stdio.h> #include <unistd.h> #include "system.h" #include "sys/alt_irq.h" #include "altera_avalon_pio_regs.h" #define ESC 27 #define ESC_TOP_LEFT "[1;0H" #define ESC_COL2_INDENT5 "[2;5H" #define ESC_CLEAR "K" #define ECS_COL1_INDENT5 "[1;5H" #endif /*COUNT_BINARY_H_*/
main.c文件:
#include "count_binary.h" int main(void) { int i; int data; while(1) { i=0; data=0x80; for(i=0;i<8;i++) { IOWR(LED_GREEN_BASE,0,data); data>>=1; usleep(500000); } } }
/*
注:
函数原型:IOWR(BASE, REGNUM, DATA) 输入参数:BASE为寄存器的基地址,REGNUM为寄存器的偏移量,DATA为要写入的数据 函数说明:往偏移量为REGNUM寄存器中写入数据。寄存器的值在地址总线的范围之内。 返回值:
*/
|
3.独立键盘
count_binary.h文件见上
main.c文件
/* 硬件环境:DE2开发板 按键未按时是高电平 按下后是低电平 4个按键控制4个灯(配置的系统有八个灯,4个键只点亮高四位的灯) */ #include "count_binary.h" int alt_main() { int key,data; data=0x00; while(1) { key=IORD(BUTTON_PIO_BASE,0); if(key==0x7) data=0x80; key=IORD(BUTTON_PIO_BASE,0); if(key==0xb) data=0x40; key=IORD(BUTTON_PIO_BASE,0); if(key==0xd) data=0x20; key=IORD(BUTTON_PIO_BASE,0); if(key==0xe) data=0x10; IOWR(LED_GREEN_BASE,0,data); } }
/*
IO操作函数 函数原型:IORD(BASE, REGNUM) 输入参数:BASE为寄存器的基地址,REGNUM为寄存器的偏移量 函数说明:从基地址为BASE的设备中读取寄存器中偏移量为REGNUM的单元里面的值。寄存器的值在地址总线的范围之内。 返回值: -
*/ |
说明: 下面的程序采用的是另一套配置文件,即ptf文件同上面的不同,是DE2开发板自带的,用起来挺方便! 4.外部中断点亮数码管
/* 硬件环境:DE2开发板 四个按键对应着四个不同的外部中断 通过不同的按键在数码管上面显示不同的数字 */ #include "count_binary.h" volatile int edge_capture; /*外部中断服务子函数声明(与单片机不同,这里需要声明一下)*/ static void handle_button_interrupts(void *context,alt_u32 id); /*按键初始化*/ static void init_button_pio() { void *edge_capture_ptr=(void*)&edge_capture; /*使能四个按键的中断(外部中断)*/ IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE,0xf); /*复位边沿捕获寄存器*/ IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE,0x0); /*注册四个按键锁对应的外部中断*/ alt_irq_register(BUTTON_PIO_IRQ,edge_capture_ptr,handle_button_interrupts); } /*主函数*/ int main(void) { init_button_pio(); while(1) { switch(edge_capture) { /*按键3按下时8个数码管全部显示1*/
case 0x08: IOWR(SEG7_DISPLAY_BASE,0,0x11111111); break; case 0x04: IOWR(SEG7_DISPLAY_BASE,0,0X22222222); break; case 0x02: IOWR(SEG7_DISPLAY_BASE,0,0X33333333); break; /*按键0按下时8个数码管全部显示4*/ case 0x01: IOWR(SEG7_DISPLAY_BASE,0,0x44444444); break; } } }
/*外部中断服务子函数*/ static void handle_button_interrupts(void *context,alt_u32 id) { volatile int * edge_capture_ptr=(volatile int *)context; /*键按键的值存储到边沿捕获寄存器中*/ *edge_capture_ptr=IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE); /*复位边沿捕获寄存器*/ IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE,0); } |
5.定时器 #include "count_binary.h" int alt_main() { int second=0; while(1) { usleep(100000); second++; IOWR(SEG7_DISPLAY_BASE,0,second); } } |
6.1602液晶驱动程序
lcd.h文件
#ifndef LCD_H_ #define LCD_H_ #define lcd_write_cmd(base,data) IOWR(base,0,data) #define lcd_read_cmd(base) IORD(base,1) #define lcd_write_data(base,data) IOWR(base,2,data) #define lcd_read_data(base) IORD(base,3) void lcd_init(); void lcd_show_text(char * text); void lcd_line2(); void lcd_test(); #endif /*LCD_H_*/
main.c文件
/*硬件环境:DE2开发板 * 软件环境:quaters II 7.2,NIOS II 7.2 * 函数功能:1602液晶驱动程序 */ #include <unistd.h> #include <string.h> #include <io.h> #include "system.h" #include "lcd.h" void lcd_init() { /*采用8位数据总线的方式,两行显示*/ lcd_write_cmd(LCD_16207_0_BASE,0X38); usleep(2000); /*关显示,关光标闪烁方式*/ lcd_write_cmd(LCD_16207_0_BASE,0X0C); usleep(2000); /*清显示*/ lcd_write_cmd(LCD_16207_0_BASE,0X01); usleep(2000); /*光标前移方式,不允许整屏移动*/ lcd_write_cmd(LCD_16207_0_BASE,0X06); usleep(2000); /*显示指针指向处事位置*/ lcd_write_cmd(LCD_16207_0_BASE,0X80); usleep(2000); } /*显示一行字符*/ void lcd_show_text(char * text) { int i; for(i=0;i<strlen(text);i++) { lcd_write_data(LCD_16207_0_BASE,text); usleep(2000); } } void lcd_line1() { lcd_write_cmd(LCD_16207_0_BASE,0X80); usleep(2000); } /*换行,即切换到第二行*/ void lcd_line2() { lcd_write_cmd(LCD_16207_0_BASE,0XC0); usleep(2000); } int main() { char text1[16]="Wu Qin De Shi"; char text2[16]="Jie,Wu Qin De Ni"; lcd_init();//液晶初始化 while(1) { /*切换到第一行*/ lcd_line1(); /*显示第一行字符*/ lcd_show_text(text1); /*切换到第二行*/ lcd_line2(); /*显示第二行字符*/ lcd_show_text(text2); usleep(4000000); lcd_write_cmd(LCD_16207_0_BASE,0X01);//清屏 usleep(2000); /*切换到第一行*/ lcd_line1(); lcd_show_text("Liu Ya Li,"); lcd_line2(); /*显示第二行字符*/ lcd_show_text("I Love You!"); usleep(4000000); } return 0; } |
7.1602用NIOS II 的fprintf标准函数控制显示 /*硬件环境:DE2开发板 * 软件环境:quaters II 7.2,NIOS II 7.2 * 函数功能:1602液晶驱动程序 * 使用NIOS II的fprintf标准函数对lcd编程比较简单! */ #include <unistd.h> #include <stdio.h> #include <string.h> #include <io.h> #include "system.h" int main(void) { FILE *lcd; lcd=fopen("/dev/lcd_16207_0","w"); /*1602液晶第一行显示的内容*/ fprintf(lcd,"I love NIOS II!\n"); /*1602液晶第二行显示的内容*/ fprintf(lcd,"I love you!"); fclose(lcd); return 0; }
|
8.综合例程
count_binary.h文件
#ifndef COUNT_BINARY_H_ #define COUNT_BINARY_H_ #include "alt_types.h" #include <stdio.h> #include <unistd.h> #include "system.h" #include "sys/alt_irq.h" #include "altera_avalon_pio_regs.h" #define ESC 27 #define ESC_TOP_LEFT "[1;0H" #define ESC_COL2_INDENT5 "[2;5H" #define ESC_CLEAR "K" #define ECS_COL1_INDENT5 "[1;5H" #endif /*COUNT_BINARY_H_*/
main.c文件
#include "count_binary.h" static alt_u8 count; volatile int edge_capture; #ifdef BUTTON_PIO_BASE static void handle_button_interrupts(void *context,alt_u32 id) { volatile int *edge_capture_ptr=(volatile int *)context; *edge_capture_ptr=IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE,0); } static void init_button_pio() { void *edge_capture_ptr=(void *)&edge_capture; IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE,0XF); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE,0X0); alt_irq_register(BUTTON_PIO_IRQ,edge_capture_ptr,handle_button_interrupts); } #endif #ifdef SEG7_DISPLAY_BASE static void sevenseg_set_hex(int hex) { static alt_u8 segments[16]={0x81,0xcf,0x92,0x86,0xcc,0xa4,0xa0,0x8f,0x80,0x84, 0x88,0xe0,0xf2,0xc2,0xb0,0xb8};
unsigned int data=segments[hex&15]|(segments[(hex>>4)&15]<<8); IOWR_ALTERA_AVALON_PIO_DATA(SEG7_DISPLAY_BASE,data); } #endif
static void lcd_init(FILE *lcd) { fprintf(lcd,"%c%s Counting will be displayed below...",ESC,ESC_TOP_LEFT); } static void initial_message() { }
static void count_led() { #ifdef LED_RED_BASE IOWR_ALTERA_AVALON_PIO_DATA(LED_RED_BASE,count); #endif } static void count_sevenseg() { #ifdef SEG7_DISPLAY_BASE sevenseg_set_hex(count); #endif } static void count_lcd(void *arg) { FILE *lcd=(FILE*)arg; fprintf(lcd,"%c%s 0x%x\n",ESC,ESC_COL2_INDENT5,count); } static void count_all(void *arg) { count_led(); count_sevenseg(); count_lcd(arg); printf("%02x, ",count); } static void handle_button_press(alt_u8 type,FILE *lcd) { if(type=='c') { switch(edge_capture) { case 0x1: count_led();break; case 0x2: count_sevenseg();break; case 0x4: count_lcd(lcd);break; case 0x8: count_all(lcd);break; default: count_all(lcd);break; } } } int main(void) { int i; int wait_time; FILE *lcd; count=0; lcd=fopen("/dev/lcd_16207_0","w"); #ifdef BUTTON_PIO_BASE //init_button_pio(); init_button_pio(); #endif initial_message(); while(1) { usleep(100000); if(edge_capture!=0) { handle_button_press('c',lcd); } else { count_all(lcd); } if(count==0xff) { fprintf(lcd,"%c%s Waiting...\n",ESC,ESC_TOP_LEFT,ESC,ESC_CLEAR, ESC,ESC_COL2_INDENT5); edge_capture=0; fprintf(lcd,"%c%s",ESC,ESC_COL2_INDENT5,ESC,ESC_CLEAR); wait_time=0; for(i=0;i<70;++i) { wait_time=i/10; fprintf(lcd,"%c%s",ESC,ESC_COL2_INDENT5,wait_time); if(edge_capture!=0) { handle_button_press('w',lcd); usleep(100000); } } initial_message(); lcd_init(lcd); } count++; } fclose(lcd); return(0); } |
9.定时器1中断+流水灯
#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" static void timer1_init(void); //初始化中断 int i = 0; /*主函数*/ int main(void) { //初始化Timer timer1_init(); while(1); return 0; }
/*定时器1中断服务子函数*/ static void ISR_timer1(void *context, alt_u32 id) { //控制流水灯闪烁,一共8个LED IOWR_ALTERA_AVALON_PIO_DATA(LED_GREEN_BASE, 1<<i); i++; if(i == 8) i = 0; //清除Timer中断标志寄存器 IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_1_BASE, 0x00); }
/*定时器1初始化函数*/ void timer1_init(void) //初始化中断 { //清除Timer1中断标志寄存器 IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_1_BASE, 0x00); //设置Timer1周期T=25000000/5000000=0.5s //设定定时器的低16位 IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_1_BASE,25000000); //设定定时器的高16位 IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_1_BASE,25000000 >> 16); //Timer1中断使能 IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_1_BASE, 0x07); //注册Timer1中断 alt_irq_register(TIMER_1_IRQ, (void *)TIMER_1_BASE, ISR_timer1); }
|
10.定时器1+数码管显示
#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" static void timer1_init(void); //初始化中断 unsigned long int i = 0; /*主函数*/ int main(void) { //初始化Timer timer1_init(); while(1); return 0; }
/*定时器1中断服务子函数*/ static void ISR_timer1(void *context, alt_u32 id) { //在8个7段数码管上面完成计数 IOWR(SEG7_DISPLAY_BASE,0,i); i++; //清除Timer中断标志寄存器 IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_1_BASE, 0x00); }
/*定时器1初始化函数*/ void timer1_init(void) //初始化中断 { //清除Timer1中断标志寄存器 IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_1_BASE, 0x00); //设置Timer1周期T=25000000/5000000=0.5s //设定定时器的低16位 IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_1_BASE,25000000); //设定定时器的高16位 IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_1_BASE,25000000 >> 16); //Timer1中断使能 IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_1_BASE, 0x07); //注册Timer1中断 alt_irq_register(TIMER_1_IRQ, (void *)TIMER_1_BASE, ISR_timer1); }
|
11.定时器1和2+流水灯+数码管显示
/*硬件环境:DE2开发板 * 软件环境:NIOS II7.2,QUATERS II 7.2 * 本程序有定时器1控制灯的闪烁 * 由定时器2控制定时器1的周期 * */ #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" /*注:我自己的DE2的system.h文件中的两个定时器分别是TIMER_0和TIMER_1 * 而我直接采用的是黑金刚开发板的程序 * 在system.h 文件中 * #define TIMER_0_BASE 0x00681020 * #define TIMER_0_IRQ 3 * #define TIMER_1_BASE 0x00681040 * #define TIMER_1_IRQ 4 * 故而需做修改如下:*/ #define TIMER1_IRQ 3 #define TIMER2_IRQ 4 #define TIMER1_BASE 0x00681020 #define TIMER2_BASE 0x00681040 static void timer_init(void); //初始化中断
int i = 0,j = 0,flag; alt_u32 timer_prd[4] = {5000000, 10000000, 50000000, 100000000};//定时器的周期 //T1依次为0.1s,0.2s,1s,2s int main(void) { //初始化Timer timer_init();
while(1); return 0; } static void ISR_timer1(void *context, alt_u32 id) { //控制流水灯闪烁,一共8个LED IOWR(LED_GREEN_BASE,0,i); //数码管显示 IOWR(SEG7_DISPLAY_BASE,0,i); i++; if(i == 255) i = 0;
//清除Timer中断标志寄存器 IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER1_BASE, 0x00); } /*用定时器2改变定时器1的周期*/ static void ISR_timer2(void *context, alt_u32 id) { //改变定时器1的周期T1=timer_prd[j]/50M(单位:秒) 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); } 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周期 T2=400M/50M=8s; 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); }
|
12.串口程序
/*硬件环境:DE2开发板 * 软件环境:NIOS II 7.2,QUATERS II 7.2 * 本程序主要功能: * 1.每隔1秒钟用串口向外发送一个字符串 * 2.当用串口调试助手向其发送0-9这9个数字时,八个数码管都依次显示0-9 * */ /*配置的系统的波特率是115200*/ #include "altera_avalon_uart_regs.h" #include "system.h" #include "altera_avalon_pio_regs.h" #include "alt_types.h" #include "sys/alt_irq.h" #include <stdio.h> #include <string.h> #define UART_BASE 0x00681000 #define UART_IRQ 2 #define TIME_DELAY 1000000//1M,即一秒 //UART发送一个字节子程序 void Uart_send(unsigned char data) { alt_u16 status; status=IORD_ALTERA_AVALON_UART_STATUS(UART_BASE); while(!(status&0x0040))//等待发送完成 status=IORD_ALTERA_AVALON_UART_STATUS(UART_BASE); IOWR_ALTERA_AVALON_UART_TXDATA(UART_BASE,data); } //UART发送多个字节子程序 void Uart_send_n(unsigned char *ptr) { while(*ptr) { Uart_send(*ptr); ptr++; } Uart_send(0x0a);//显示完一个字符串就回车换行 }
//UART接收子程序 int Uart_receive(void) { alt_u16 status; int temp; status=IORD_ALTERA_AVALON_UART_STATUS(UART_BASE); while(!(status&0x0080))//等待发送完成 status=IORD_ALTERA_AVALON_UART_STATUS(UART_BASE); temp=IORD_ALTERA_AVALON_UART_RXDATA(UART_BASE); return temp; } //串口接收中断服务程序 void Uart_ISR(void * context,alt_u32 id) { unsigned char temp; temp=IORD_ALTERA_AVALON_UART_RXDATA(UART_BASE); switch(temp) { case '0': IOWR(SEG7_DISPLAY_BASE,0,0x00000000);break; case '1': IOWR(SEG7_DISPLAY_BASE,0,0x11111111);break; case '2': IOWR(SEG7_DISPLAY_BASE,0,0x22222222);break; case '3': IOWR(SEG7_DISPLAY_BASE,0,0x33333333);break; case '4': IOWR(SEG7_DISPLAY_BASE,0,0x44444444);break; case '5': IOWR(SEG7_DISPLAY_BASE,0,0x55555555);break; case '6': IOWR(SEG7_DISPLAY_BASE,0,0x66666666);break; case '7': IOWR(SEG7_DISPLAY_BASE,0,0x77777777);break; case '8': IOWR(SEG7_DISPLAY_BASE,0,0x88888888);break; case '9': IOWR(SEG7_DISPLAY_BASE,0,0x99999999);break; } } //串口中断初始化 void Uart_init() { IOWR_ALTERA_AVALON_UART_CONTROL(UART_BASE, 0x80);//接收中断使能 IOWR_ALTERA_AVALON_UART_STATUS(UART_BASE, 0x0);//清状态标志 // IOWR_ALTERA_AVALON_UART_RXDATA(UART_BASE, 0x0);//清接收寄存器 alt_irq_register(UART_IRQ,0,Uart_ISR); } int main() { Uart_init(); while(1) { Uart_send_n("Liu Ya Li,I love u!"); //Uart_send_n(64); usleep(TIME_DELAY);//延时一微秒 } }
|
13.定时器1和2(总共有timer0,timer1,timer2这三个定时器,在原有的两个的基础上加了个定时器2)
#define timer2 #ifdef timer2 #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" //#define TIMER_2_BASE 0x01b02060 //#define TIMER_2_IRQ 9 static void timer2_init(void); //初始化中断 unsigned long int i = 0; /*主函数*/ int main(void) { //初始化Timer timer2_init(); while(1); return 0; }
/*定时器2中断服务子函数*/ static void ISR_timer2(void *context, alt_u32 id) { //在8个7段数码管上面完成计数 IOWR(SEG7_DISPLAY_BASE,0,i); i++; //清除Timer2中断标志寄存器 IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_2_BASE, 0x00); }
/*定时器1初始化函数*/ void timer2_init(void) //初始化中断 { //清除Timer2中断标志寄存器 IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_2_BASE, 0x00); //设置Timer2周期T=1s //设定定时器的低16位 IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_2_BASE,100000000); //设定定时器的高16位 IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_2_BASE,100000000 >> 16); //Timer1中断使能 IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_2_BASE, 0x07); //注册Timer2中断 alt_irq_register(TIMER_2_IRQ, (void *)TIMER_2_BASE, ISR_timer2); } #else #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" static void timer1_init(void); //初始化中断 unsigned long int i = 0; /*主函数*/ int main(void) { //初始化Timer timer1_init(); while(1); return 0; }
/*定时器1中断服务子函数*/ static void ISR_timer1(void *context, alt_u32 id) { //在8个7段数码管上面完成计数 IOWR(SEG7_DISPLAY_BASE,0,i); i++; //清除Timer中断标志寄存器 IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_1_BASE, 0x00); }
/*定时器1初始化函数*/ void timer1_init(void) //初始化中断 { //清除Timer1中断标志寄存器 IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_1_BASE, 0x00); //设置Timer1周期T=1s //设定定时器的低16位 IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_1_BASE,100000000); //设定定时器的高16位 IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_1_BASE,100000000 >> 16); //Timer1中断使能 IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_1_BASE, 0x07); //注册Timer1中断 alt_irq_register(TIMER_1_IRQ, (void *)TIMER_1_BASE, ISR_timer1); }
#endif
|
14.对SDRAM进行读写操作
首先,对memest()函数进行一下介绍。
memest原型 (please type "man memset" in your shell)
void *memset(void *s, int c, size_t n);
memset:作用是在一段内存块中填充某个给定的值,它对较大的结构体或数组进行清零操作的一种最快方法。
常见的三种错误
第一: 搞反了c 和 n的位置.
一定要记住 如果要把一个char a[20]清零, 一定是 memset(a, 0, 20) 而不是 memset(a, 20, 0)
第二: 过度使用memset, 我想这些程序员可能有某种心理阴影, 他们惧怕未经初始化的内存, 所以他们会写出这样的代码:
char buffer[20];
memset(buffer, 0, sizeof((char)*20)); strcpy(buffer, "123");
这里的memset是多余的. 因为这块内存马上就被覆盖了, 清零没有意义.
第三: 其实这个错误严格来讲不能算用错memset, 但是它经常在使用memset的场合出现
int some_func(struct something *a){ … … memset(a, 0, sizeof(a)); … }
问:为何要用memset置零?memset( &Address, 0, sizeof(Address));经常看到这样的用法,其实不用的话,分配数据的时候,剩余的空间也会置零的。
答:1.如果不清空,可能会在测试当中出现野值。 你做下面的试验看看结果()
char buf[5];
CString str,str1; //memset(buf,0,sizeof(buf)); for(int i = 0;i<5;i++) { str.Format(“%d “,buf); str1 +=str ; } TRACE(“%s\r\n“,str1)
2.其实不然!特别是对于字符指针类型的,剩余的部分通常是不会为0的,不妨作一个试验,定义一个字符数组,并输入一串字符,如果不用memset实现清零,使用MessageBox显示出来就会有乱码(0表示NULL,如果有,就默认字符结束,不会输出后面的乱码)
问:
如下demo是可以的,能把数组中的元素值都设置成字符1, #include <iostream> #include <cstring> using namespace std; int main() { char a[5]; memset(a,'1',5); for(int i = 0;i < 5;i++) cout<<a<<" "; system("pause"); return 0; }
#include <stdio.h> //#include "../inc/sopc.h" #include "system.h" #include "string.h" #include "unistd.h" #include "altera_avalon_pio_regs.h" /*在DE2开发板相对应的system.h文件中定义的是SDRAM_0_BASE * #define SDRAM_0_BASE 0x00800000,所以有如下宏定义 */ #define SDRAM_BASE 0x00800000 unsigned short * ram = (unsigned short *)(SDRAM_BASE+0x10000); //SDRAM地址
int main(void) { int i; memset(ram,0,100); //从这里可以看出SDRAM的读写速度有多么的快!!! //向ram中写数据,当ram写完以后,ram的地址已经变为(SDRAM_BASE+0x10100) for(i=0;i<100;i++) { *(ram++) = i; } //逆向读取ram中的数据 for(i=0;i<100;i++){ printf("%d\n",*(--ram)); } for(i=100;i<200;i++) { *(ram++) = i; } //逆向读取ram中的数据 for(i=100;i<200;i++) { IOWR(SEG7_DISPLAY_BASE,0,*(--ram)); printf("%d\n",*(--ram)); usleep(1000000); } return 0; }
|
15.不使用API的流水灯
#include "system.h" #define _LED typedef struct { unsigned long int DATA; unsigned long int DIRECTION; unsigned long int INTERRUPT_MASK; unsigned long int EDGE_CAPTURE; } PIO_STR;
#ifdef _LED #define LED ((PIO_STR *)LED_GREEN_BASE) #endif
#include "unistd.h" #include "stdio.h" unsigned int i=0; int main() { while(1) { for(i=0;i<8;i++) { LED->DATA=1<<i; usleep(1000000);//延时1秒 } } }
流水灯2:
#include "system.h" #include "unistd.h" #include "stdio.h" /*结构体的定义*/ typedef struct { unsigned long int DATA; unsigned long int DIRECTION; unsigned long int INTERRUPT_MASK; unsigned long int EDGE_CAPTURE; } PIO_STR; /*绿灯的定义*/ #define LED_GREEN ((PIO_STR *)LED_GREEN_BASE) /*红灯的定义*/ #define LED_RED ((PIO_STR *)LED_RED_BASE) /*按键的定义*/ #define KEY ((PIO_STR *)BUTTON_PIO_BASE)
unsigned int i=0; int main() { while(1) { for(i=0;i<18;i++) { LED_RED->DATA=1<<i; LED_GREEN->DATA=1<<i; usleep(500000);//延时0.5秒 } } }
需要注意的是:
当你的CPU选择的是NIOS II/f(最高级的那种)的时候,在高速缓存的配置的地方要注意一下,应选择none,否则
灯是不会亮的!如果选择的是其他两种CPU的话,就不用注意这种问题:
 500)this.width=500;" border=0>
|
16.定时器1+数码管计数 注:以下代码是自己配置的ptf文件上运行的,也就是说目前本篇文章用了三个不同的ptf文件
/* 硬件环境: DE2开发板 * 软件环境:QUATERS II 7.2,NIOS II 7.2 * 编写时间:2010.7.17 * 功能:8个数码管加定时器1计数 * 定时器1周期T=timer_1_period/50000000 * */ #include "system.h" #include "altera_avalon_pio_regs.h" #include "altera_avalon_timer_regs.h" #include "sys/alt_irq.h" #include <io.h> #define timer_1_period 50000 #define uint unsigned int #define uchar unsigned char
alt_u32 count=0; uchar seg_table[11]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x7f}; void isr_timer_1(); /*定时器1的初始化*/ void timer_1_init() { /*清除定时器1的中断标志*/ IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_1_BASE,0X00); /*设定定时器周期的低16位*/ IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_1_BASE,timer_1_period); /*设定定时器周期的高16位*/ IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_1_BASE,timer_1_period>>16); /*定时器1中断使能*/ IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_1_BASE,0X07); /*对定时器1中断进行注册*/ alt_irq_register(TIMER_1_IRQ, (void *)TIMER_1_BASE, isr_timer_1); } /*定时器1的中断服务子函数*/ void isr_timer_1() { count++; /*清除定时器1的中断标志*/ IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_1_BASE,0X00); } /*数码管显示子函数*/ void seg_display(alt_u32 z) { if(z<10) { IOWR(SEG0_DISPLAY_BASE,0,seg_table[z%10]); IOWR(SEG1_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG2_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG3_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG4_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG5_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG6_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG7_DISPLAY_BASE,0,seg_table[10]); } else if(z<100) { IOWR(SEG0_DISPLAY_BASE,0,seg_table[z%10]); IOWR(SEG1_DISPLAY_BASE,0,seg_table[z%100/10]); IOWR(SEG2_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG3_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG4_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG5_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG6_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG7_DISPLAY_BASE,0,seg_table[10]); } else if(z<1000) { IOWR(SEG0_DISPLAY_BASE,0,seg_table[z%10]); IOWR(SEG1_DISPLAY_BASE,0,seg_table[z%100/10]); IOWR(SEG2_DISPLAY_BASE,0,seg_table[z%1000/100]); IOWR(SEG3_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG4_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG5_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG6_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG7_DISPLAY_BASE,0,seg_table[10]); } else if(z<10000) { IOWR(SEG0_DISPLAY_BASE,0,seg_table[z%10]); IOWR(SEG1_DISPLAY_BASE,0,seg_table[z%100/10]); IOWR(SEG2_DISPLAY_BASE,0,seg_table[z%1000/100]); IOWR(SEG3_DISPLAY_BASE,0,seg_table[z%10000/1000]); IOWR(SEG4_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG5_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG6_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG7_DISPLAY_BASE,0,seg_table[10]); } else if(z<100000) { IOWR(SEG0_DISPLAY_BASE,0,seg_table[z%10]); IOWR(SEG1_DISPLAY_BASE,0,seg_table[z%100/10]); IOWR(SEG2_DISPLAY_BASE,0,seg_table[z%1000/100]); IOWR(SEG3_DISPLAY_BASE,0,seg_table[z%10000/1000]); IOWR(SEG4_DISPLAY_BASE,0,seg_table[z%100000/10000]); IOWR(SEG5_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG6_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG7_DISPLAY_BASE,0,seg_table[10]); } else if(z<1000000) { IOWR(SEG0_DISPLAY_BASE,0,seg_table[z%10]); IOWR(SEG1_DISPLAY_BASE,0,seg_table[z%100/10]); IOWR(SEG2_DISPLAY_BASE,0,seg_table[z%1000/100]); IOWR(SEG3_DISPLAY_BASE,0,seg_table[z%10000/1000]); IOWR(SEG4_DISPLAY_BASE,0,seg_table[z%100000/10000]); IOWR(SEG5_DISPLAY_BASE,0,seg_table[z%1000000/100000]); IOWR(SEG6_DISPLAY_BASE,0,seg_table[10]); IOWR(SEG7_DISPLAY_BASE,0,seg_table[10]); } else if(z<10000000) { IOWR(SEG0_DISPLAY_BASE,0,seg_table[z%10]); IOWR(SEG1_DISPLAY_BASE,0,seg_table[z%100/10]); IOWR(SEG2_DISPLAY_BASE,0,seg_table[z%1000/100]); IOWR(SEG3_DISPLAY_BASE,0,seg_table[z%10000/1000]); IOWR(SEG4_DISPLAY_BASE,0,seg_table[z%100000/10000]); IOWR(SEG5_DISPLAY_BASE,0,seg_table[z%1000000/100000]); IOWR(SEG6_DISPLAY_BASE,0,seg_table[z%10000000/1000000]); IOWR(SEG7_DISPLAY_BASE,0,seg_table[10]); } else if(z<100000000) { IOWR(SEG0_DISPLAY_BASE,0,seg_table[z%10]); IOWR(SEG1_DISPLAY_BASE,0,seg_table[z%100/10]); IOWR(SEG2_DISPLAY_BASE,0,seg_table[z%1000/100]); IOWR(SEG3_DISPLAY_BASE,0,seg_table[z%10000/1000]); IOWR(SEG4_DISPLAY_BASE,0,seg_table[z%100000/10000]); IOWR(SEG5_DISPLAY_BASE,0,seg_table[z%1000000/100000]); IOWR(SEG6_DISPLAY_BASE,0,seg_table[z%10000000/1000000]); IOWR(SEG7_DISPLAY_BASE,0,seg_table[z%100000000/10000000]); } } /*主函数*/ int main() { timer_1_init(); while(1) { seg_display(count); } } |
|
|
文章评论(0条评论)
登录后参与讨论