注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

东月之神

在单纯的观念里面,生命就容易变得比较深刻!

 
 
 

日志

 
 
关于我

别驻足,梦想要不停追逐,别认输,熬过黑暗才有日出,要记住,成功就在下一步,路很苦,汗水是最美的书!

网易考拉推荐

NIOS II 学习笔记(一)(转)  

2011-08-20 16:15:40|  分类: FPGA |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
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 学习笔记:
    在这里先简单介绍一下各头文件的作用,,<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[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 <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;
  评论这张
 
阅读(1278)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017