4个led对应一个PIO口的4bits位宽或者4个PIO口;Bidir为双向(对应于外部,接IO口),一根信号线即可输出入,而InOut则有两根信号线,接内部逻辑;初始化值1111十六进制为f
四个寄存器:data、IRQ Generation(中断)、direction、edgecapture(边沿捕获)
任务:2个按键,当按键0按下时,LED灯开始闪烁;当按键1按下时,LED灯停止闪烁。
要求:使用一个PIO,设置为6位(驱动4个LED灯和2个按键),能够捕获下降沿、产生中断(边沿)、使能单独位的设置和清零、使能边沿捕获寄存器的单独位清零
步骤:
1.Qsys的PIO核设置
2.硬件verilog
module nios_pio_led(
clk,
rst_n,
key,
key_gnd
led
); //端口定义
input clk;
input rst_n;
output key_gnd;
inout [1:0]key;
inout [3:0]led;
assign key_gnd = 0;
mysystem u0 (
.clk_clk (clk), // clk.clk
.reset_reset_n (rst_n), // reset.reset_n
.pio_led_export (key,led) // pio_led.export
);
endmodule
3.软件代码
软件比较逻辑
#include <stdio.h>
#include "system.h"
#include "altera_avalon_pio_regs.h"
#include <alt_types.h>
int main()
{
alt_u8_led = 0;
alt_u32 i;
alt_u8 data, data_pre; //存储按键读到的值
alt_u8 led_en; //led使能信号
data = 0x3; //0x3是两个按键为11 每四个二进制代表一个十六进制,2^1+2^0=3
led_en = 0;
IOWR_ALTERA_AVALON_PIO_DIRECTION(PIO_LED_BASE, 0x0f); //设置低四位为输出,高两位为输入 (1111)=f
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(PIO_LED_BASE, 0); //不使用中断,因此要关闭所有bit的中断
while(1)
{
data_pre = data;
data = IORD_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE);
data = data >> 4; //右移4位,没有按下时为00110000移位后为00000011,移到低位好判断
if(data != data_pre)
{
if(data == 0x2 ) //0x2=0010说明按键0被按下了
{
led_en = 1;
}
}
if(led_en == 1)
{
led = 0;
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, led); //点亮LED灯
i = 0;
while(i<500000) //延时功能,非明确延时,数值太小将无法看到灯的闪烁效果
{
//判断按键1是否按下
data_pre = data;
data = IORD_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE);
data = data >> 4; //右移4位,没有按下时为00110000移位后为00000011,移到低位好判断
if(data != data_pre)
{
if(data == 0x1 ) //0x1=0001说明按键1被按下了
{
led_en = 0;
}
}
i++;
}
led = 0x0f; //关闭led灯
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, led); //熄灭LED灯
i = 0;
while(i<500000) //延时功能,非明确延时,数值太小将无法看到灯的闪烁效果
{
i++;
}
}
}
return 0;
}
用边沿捕获——硬件逻辑
原理:边沿捕获寄存器捕获一个边沿时,该寄存器会设置为1。
Enable bit-clearing for edge capture register该选项打开,则可以单独清零每一位,否则清零时是清零所有位。
#include <stdio.h>
#include "system.h"
#include "altera_avalon_pio_regs.h"
#include <alt_types.h>
int main()
{
alt_u8_led = 0;
alt_u32 i;
alt_u8 data, data_pre; //存储按键读到的值
alt_u8 led_en; //led使能信号
data = 0x3; //0x3是两个按键为11 每四个二进制代表一个十六进制,2^1+2^0=3
led_en = 0;
IOWR_ALTERA_AVALON_PIO_DIRECTION(PIO_LED_BASE, 0x0f); //设置低四位为输出,高两位为输入 (1111)=f
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(PIO_LED_BASE, 0); //不使用中断,因此要关闭所有bit的中断
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_LED_BASE, 0x30); //清零所有捕获位
while(1)
{
data = IORD_ALTERA_AVALON_PIO_EDGE_CAP(PIO_LED_BASE)
data = data >> 4; //右移4位,没有按下时为00110000移位后为00000011,移到低位好判断
if(data & 0x1) //按位与
{
led_en = 1;
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_LED_BASE, 0x30); //清零所有捕获位
}
if(led_en == 1)
{
led = 0;
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, led); //点亮LED灯
i = 0;
while(i<500000) //延时功能,非明确延时,数值太小将无法看到灯的闪烁效果
{
//判断按键1是否按下
data = IORD_ALTERA_AVALON_PIO_EDGE_CAP(PIO_LED_BASE)
data = data >> 4; //右移4位,没有按下时为00110000移位后为00000011,移到低位好判断
if(data & 0x2) //按位与
{
led_en = 0;
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_LED_BASE, 0x30); //清零所有捕获位
}
i++;
}
led = 0x0f; //关闭led灯
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, led); //熄灭LED灯
i = 0;
while(i<500000) //延时功能,非明确延时,数值太小将无法看到灯的闪烁效果
{
i++;
}
}
}
return 0;
}