nios ii

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
#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库函数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 学习笔记:
    在这里先简单介绍一下各头文件的作用,,这个头文件包含了标准输入、输出、错误函数库;"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<       usleep(500000); //延时0.5秒
    }
  }
  return 0;
}

2.流水灯

count_binary.h文件

#ifndef COUNT_BINARY_H_
#define COUNT_BINARY_H_
#include "alt_types.h"
#include
#include
#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
#include
#include
#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    {
        lcd_write_data(LCD_16207_0_BASE,text[i]);
        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
#include
#include
#include
#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
#include
#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
#include
#include
#include
#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++;
    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
#include
#include
#include
#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
#include
#include
#include
#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
#include
#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
#include
#include
#include
#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
#include
#include
#include
#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[i]); str1 +=str ; } TRACE(“%s\r\n“,str1) 

2.其实不然!特别是对于字符指针类型的,剩余的部分通常是不会为0的,不妨作一个试验,定义一个字符数组,并输入一串字符,如果不用memset实现清零,使用MessageBox显示出来就会有乱码(0表示NULL,如果有,就默认字符结束,不会输出后面的乱码) 

问: 

如下demo是可以的,能把数组中的元素值都设置成字符1, 
#include  
#include  
using namespace std; 
int main() 

    char a[5]; 
    memset(a,'1',5); 
    for(int i = 0;i < 5;i++) 
      cout<    system("pause"); 
    return 0; 


 

#include
//#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<            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<            LED_GREEN->DATA=1<            usleep(500000);//延时0.5秒
            
        }
    }
}

 


 

需要注意的是:

当你的CPU选择的是NIOS II/f(最高级的那种)的时候,在高速缓存的配置的地方要注意一下,应选择none,否则

灯是不会亮的!如果选择的是其他两种CPU的话,就不用注意这种问题:

 

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#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);
   }
   
}

 

转载于:https://www.cnblogs.com/iamnacl/p/3517356.html

你可能感兴趣的:(nios ii)