可编程逻辑器件FPGACPLD课程设计 DE2115.docx
《可编程逻辑器件FPGACPLD课程设计 DE2115.docx》由会员分享,可在线阅读,更多相关《可编程逻辑器件FPGACPLD课程设计 DE2115.docx(17页珍藏版)》请在冰豆网上搜索。
可编程逻辑器件FPGACPLD课程设计DE2115
PLD期末课程设计NIOSII开发
姓名:
李超
学号:
PB10011049
邮箱:
lichao37@
第一章简介
1.1硬件开发
NIOSII硬件开发主要是通过使用Qsys构建NIOSII软核,软核主要包括以下几个部分:
1.NIOSIIProcessor
2.PLL
3.clock
4.sysid
5.sdramcontroller
6.LCD
7.timer
8.ps2
9.seg7
10.led
11.key
12.jtag_uart
其中使用了DE2-115SystemCD中官方范例的IP和alterauniversityprogram提供的IP。
1.2软件开发
NIOSII的软件开发部分主要实现了以下几个功能:
13.点亮LED
14.KEY中断
15.定时器中断
16.七段数码管
17.LCD显示字符
18.PS2键盘
19.PS2鼠标
1.3基本系统搭建
DE2-115板子上提供的时钟只有50MHz,利用PLL产生三路时钟,clk0为100MHz提供给CPU和需要高速时钟的模块,如:
SRAM、SDcard、Jtag_uart等;clk1为相移-65°的100MHz,提供给SDRAM;Mclk2为10MHz提供给那些不需要高速时钟的模块,如:
key,led,lcd,timerps2等。
这样就可以根据系统的需要来选择不同的时钟。
CPU选择NIOSII/f型,储存单元选择SDRAM。
第二章基本功能开发
2.1点亮LED
在Qsys中添加PIO模块,由于红色LED有18个,所以PIO模块中width选择18,direction选择output,其他不变,如下图所示。
编译、分配管脚等步骤后,在NIOSIIIDE中system.h可以看到关于LED的相关宏定义。
根据LED_BASE就可以读写相应寄存器,实现LED的打开和熄灭。
利用PIO读写函数实现了下面几个函数,用来控制LED。
voidled(inttemp)//根据temp的每一个bit决定么个LED的状态。
//如temp=5即0101,则第1个LED和第三个LED点亮,其他熄灭
{
IOWR_ALTERA_AVALON_PIO_DATA(LEDR_BASE,temp);
}
voidled_on(inti)//将第i个LED点亮。
{
inttemp=IORD_ALTERA_AVALON_PIO_DATA(LEDR_BASE);
IOWR_ALTERA_AVALON_PIO_DATA(LEDR_BASE,temp|1<
}
voidled_off(inti)//将第i个LED点亮。
{
inttemp=IORD_ALTERA_AVALON_PIO_DATA(LEDR_BASE);
IOWR_ALTERA_AVALON_PIO_DATA(LEDR_BASE,temp&(~(1<
}
voidled_toggle(inti)//将第i个LED的状态去反。
即由点亮变熄灭,由熄灭变点亮
{
if(tag[i]==0)//如果为熄灭
{
tag[i]=1;//点亮
led_on(i);
}
else//如果为点亮
{
tag[i]=0;//熄灭
led_off(i);
}
}
利用上述函数实现一个简单跑马灯,程序如下所示:
while
(1)
{
for(inti=0;i<8;i++)
{
usleep(100000);
led_on(17-i);
usleep(100000);
led_off(17-i);
}
}
2.2按键中断
在Qsys中添加PIO模块,由于按键有四个,所以width选择4,direction选择input,EdgeType选Falling,具体配置如下图所示。
key1按下时点亮LED8,key2按下时熄灭LED8,这样key1和key2就可以控制LED8的状态。
Key3按下时使LED9的状态翻转,依次熄灭、点亮。
key4按下时,7段数码管0和1显示0,即清零。
同时每个按键按下时,会在LCD上显示哪个按钮被按下。
按键中断初始化程序和中断服务程序如下所示:
/*
*按键中断服务程序
*/
voidkey_isr(void*context,alt_u32id)
{
volatileint*edge_capture_ptr=(volatilDeint*)context;
*edge_capture_ptr=IORD_ALTERA_AVALON_PIO_EDGE_CAP(KEY_BASE);
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_BASE,0xF);
//清中断边沿捕获寄存器
if(edge_capture==0x01)
{//key1
lcd_show_second_line("button1");
led_on(8);//点亮LED8
edge_capture=0x00;
}
elseif(edge_capture==0x02)
{//key2
lcd_show_second_line("button2");
led_off(8);//熄灭LED8
//IOWR(KEY_BASE,0x00,0xFD);
edge_capture=0x00;
}
elseif(edge_capture==0x04)
{//key3
led_toggle(9);//让LED9的状态取反
lcd_show_second_line("button3");
edge_capture=0x00;
}
elseif(edge_capture==0x08)
{//key4
count1=0;
lcd_show_second_line("button4");
SEG7_show(1,'0');//7段数码管0和1显示0,即清零。
SEG7_show(0,'0');
edge_capture=0x00;
}
else
{
printf("keyerror");
}
}
按键中断初始化程序
/*
*按键中断初始化程序
*/
voidkey_irq_init()
{
printf("initialkey");
void*edge_capture_ptr=(void*)&edge_capture;
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(KEY_BASE,0xF);
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_BASE,0);
alt_irq_register(KEY_IRQ,edge_capture_ptr,key_isr);
//alt_ic_isr_register(KEY_IRQ_INTERRUPT_CONTROLLER_ID,
//KEY_IRQ,
//key_isr,
//edge_capture_ptr,
//0x0);
}
2.3计数器中断
在Qsys中添加Timer,选择Full-featured特性,period选择1ms。
具体参数如下图所示:
由于Timer每1ms产生一个中断,这样在中断通过一个变量计数到1000,这样实现1000分频,即周期变成了1s。
在中断服务程序中实现了一个0到99计数的计数器,并且将数字显示中七段数码管0和1上,通过key4中断实现清零。
还实现了一个时钟,通过七段数码管显示当前时间的时、分、秒。
程序如下图所示:
/*
*计数器中断服务程序
*/
voidtimer_isr(void*context,alt_u32id)
{
//应答中断,将STATUS寄存器清零
IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE,
~ALTERA_AVALON_TIMER_STATUS_TO_MSK);
TIMER_0_counter++;
if(TIMER_0_counter==1000)
{//即1000分频。
周期1s。
led_toggle(6);
//--------------------------seg2seg3seg4seg5seg6seg7显示当前时间的时:
分:
秒。
if(time1[0]==60)
{
time1[0]=0;
time1[1]++;//分钟加1
}
SEG7_show(7,time1[0]%10+'0');//显示秒
SEG7_show(6,time1[0]/10+'0');
time1[0]++;
if(time1[1]==60)
{
time1[1]=0;
time1[2]++;//时加1
}
SEG7_show(5,time1[1]%10+'0');//显示分钟
SEG7_show(4,time1[1]/10+'0');
if(time1[2]==24)
{
time1[2]=0;
}
SEG7_show(3,time1[2]%10+'0');//显示小时
SEG7_show(2,time1[2]/10+'0');
//---------------------------seg0seg1实现0到99循环基数,每秒加一
if(count1==100)
{
count1=0;
}
SEG7_show(1,count1%10+'0');//七段数码管显示数字
SEG7_show(0,count1/10+'0');
TIMER_0_counter=0;
count1++;
}
}
/*
*计时器中断初始化程序,周期1ms
*/
voidtimer_irq_init(inthour,intmin,intsec)
{
TIMER_0_counter=0;
count1=0;
time1[0]=sec;
time1[1]=min;
time1[2]=hour;
IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE,
ALTERA_AVALON_TIMER_CONTROL_START_MSK|//START=1
ALTERA_AVALON_TIMER_CONTROL_CONT_MSK|//CONT=1
ALTERA_AVALON_TIMER_CONTROL_ITO_MSK);
alt_irq_register(TIMER_0_IRQ,0,timer_isr);
}
2.4七段数码管
在Qsys中添加SEG7模块,这个模块来自DE2-115SystemCD中官方范例的IP,参数默认即可,具体参数如下所示:
由于SEG7模块本质就是PIO,所以只需要PIO读写操作就可以控制SEG7,SEG7_show函数实现在数码管上显示字符。
代码如下所示:
#defineSEG7_SET(index,seg_mask)IOWR(SEG7_BASE,index,seg_mask)
//在第i个数码管上显示字符ch
voidSEG7_show(inti,charch)
{
if(ch>='0'&&ch<='9')
{
SEG7_SET(7-i,szMap[ch-'0']);
}
elseif(ch>='a'&&ch<='f')
{
SEG7_SET(7-i,szMap[ch-'a'+10]);
}
}
2.5LCD
在Qsys中添加16x2CharacterDisplay模块,该模块来自AlteraUniversityProgram。
实现了清零、显示字符串的功能。
/*
*cleartheline
*/
voidlcd_clear(intline)
{
alt_up_character_lcd_set_cursor_pos(char_lcd_dev,0,line);
alt_up_character_lcd_string(char_lcd_dev,"");
}
/*
*showthestringatthefirstline
*/
voidlcd_show_first_line(char*str)
{
lcd_clear(0);
alt_up_character_lcd_set_cursor_pos(char_lcd_dev,0,0);
alt_up_character_lcd_string(char_lcd_dev,str);
}
/*
*showthestringatthesecondline
*/
voidlcd_show_second_line(char*str)
{
lcd_clear
(1);
alt_up_character_lcd_set_cursor_pos(char_lcd_dev,0,1);
alt_up_character_lcd_string(char_lcd_dev,str);
}
/*
*initialLCD
*disablecursor
*/
voidlcd_init()
{
//opentheCharacterLCDport
char_lcd_dev=alt_up_character_lcd_open_dev(LCD_NAME);
if(char_lcd_dev==NULL)
printf("Error:
couldnotopencharacterLCDdevice\n");
else
printf("OpenedcharacterLCDdevice\n");
alt_up_character_lcd_init(char_lcd_dev);
alt_up_character_lcd_cursor_off(char_lcd_dev);
alt_up_character_lcd_string(char_lcd_dev,"Hello!
");
lcd_clear(0);
lcd_show_first_line("helloworld");
charsecond_row[]="MynameisLi\0";
lcd_show_second_line(second_row);
}
2.6ps2键盘
在Qsys中添加ps2模块,该模块来自AlteraUniversityProgram。
通过中断方式响应键盘,敲入一个字符,键盘中断服务程序响应,将输入得到字符显示在LCD上。
/*
*键盘输入
*/
charkbd_input(){
KB_CODE_TYPEdecode_mode;
alt_u8buffer;
charascii;
chartemp[20];
if((decode_scancode(ps2,&decode_mode,&buffer,&ascii)==0)){
ix=ix+1;
if((ix%2)==0){
ix=0;
sprintf(temp,"kbdinput:
%c",ascii);
lcd_show_first_line(temp);
printf("ch=%c",ascii);
returnascii;
}
}
return-1;
}
/*
*键盘中断服务程序
*/
voidkbd_isr(void*context,alt_u32id){
KB_CODE_TYPEdecode_mode;
alt_u8buffer;
charascii;
chartemp[20];
if((decode_scancode(ps2,&decode_mode,&buffer,&ascii)==0)){
ix=ix+1;
if((ix%2)==0){
ix=0;
sprintf(temp,"kbdinput:
%c",ascii);
lcd_show_first_line(temp);
printf("ch=%c\n",ascii);
//returnascii;
}
}
//return-1;
}
/*
*键盘初始化
*/
intkbd_init(void){
charkey;
printf("InitializingSetup\n");
ps2=alt_up_ps2_open_dev(PS2_NAME);//openPS/2device
//ps2->timeout=100;
alt_up_ps2_init(ps2);
alt_up_ps2_clear_fifo(ps2);
reset_keyboard(ps2);
printf("Readyforkeypress:
\n");
//while
(1){
//key=kbd_input();
//if(key=='1')//outputasamplevalueforaknowkeypress
//printf("%c",key);
//}
//注册中断
kbd_input();
kbd_input();
kbd_input();
kbd_input();
kbd_input();
alt_up_ps2_enable_read_interrupt(ps2);
alt_irq_register(PS2_IRQ,ps2,kbd_isr);
return0;
}
2.7ps2鼠标
Ps2鼠标和ps2键盘共用ps2模块。
通过中断方式响应中断,即点击鼠标左右键,鼠标中断服务程序响应,在LCD上显示是左键还是右键点击。
#defineLEFT_BUTTON_DOWN0
#defineRIGHT_BUTTON_DOWN1
/*
*鼠标按键解码
*
*/
intgetButton_down(alt_u8first_byte){
if((first_byte&0x08)==0x08){
if((first_byte&0x01)==1){
returnLEFT_BUTTON_DOWN;
}
if((first_byte&0x02)==0x02){
returnRIGHT_BUTTON_DOWN;
}else{
return-1;
}
}else{
return-1;
}
}
/*
*鼠标服务中断子程序
*/
voidmouse_isr(void*context,alt_u32id){
//lcd_show_first_line("1111");
alt_u8mous_info[3];
alt_up_ps2_read_data_byte(mouse,&mous_info[0]);
alt_up_ps2_read_data_byte(mouse,&mous_info[1]);
alt_up_ps2_read_data_byte(mouse,&mous_info[2]);
//lcd_show_second_line("2222");
intbutton=getButton_down(mous_info[0]);
if(button==LEFT_BUTTON_DOWN){
lcd_show_first_line("Leftbutton");
}elseif(button==RIGHT_BUTTON_DOWN){
lcd_show_first_line("Rightbutton");
}
}
/*
*鼠标初始化
*/
intmouse_irq_init(){
//init_lcd();
//setCursorPosition(50,50);
//打开鼠标设备
mouse=alt_up_ps2_open_dev(PS2_NAME);
//禁用timeout
mouse->timeout=0;
//初始化
alt_up_ps2_init(mouse);
//复位
alt_up_ps2_mouse_reset(mouse);
//清FIFO
alt_up_ps2_clear_fifo(mouse);
//设置数据接收有效让鼠标状态返回
alt_up_ps2_mouse_set_mode(mouse,MOUSE_ENABLE_DATA_REPORTING);
//重新设置采样率设为10
alt_up_ps2_mouse_set_mode(mouse,MOUSE_SET_SAMPLE_RATE);
alt_up_ps2_mouse_set_mode(mouse,10);
//设置分辨率设为2count/mm
alt_up_ps2_mouse_set_mode(mouse,MOUSE_SET_RESOLUTION);
alt_up_ps2_mouse_set_mode(mouse,0x02);
alt_up_ps2_enable_read_interrupt(mouse);
//开中断
//IOWR_ALT_UP_PS2_PORT_CONTROL(PS2_BASE,0x01);
//启动流模式
alt_up_ps2_mouse_set_mode(mouse,MOUSE_STREAM_MODE);
//查看设备信息
alt_up_ps2_mouse_set_mode(mo