基于NIOS-II的示波器:PART1 按键&显示屏驱动&界面
NIOS II 相关资料以及基础入门
《NiosII的奇幻漂流》
《Nios II那些事儿》
本文所有的硬件基础以及工程参考来自魏坤示波仪,重新实现驱动并重构工程。
基于NIOS II的示波器实现
Version 0.1 按键驱动&显示屏驱动&界面实现
Part 0.1.0 硬件准备
由于屏幕会挡住烧录口,这里飞线以供调试。
Part 0.1.1 创建Quartus工程
软核部分:利用SOPC Builder建立kernel,软核具体配置如下
- 由于显示芯片利用的
ILI9481,这里利用LCD前缀字样PIO口与LCD芯片通信,利用、PWM_LED控制LCD的亮度 - 利用
KEY_PORT读取按键的输入
这里待补全各组件参数设置
- 由于显示芯片利用的
顶层图
其中
SYS_PLL输出S0S1均为100MHZ的时钟信号而
pwm_controller则通过计数器控制屏幕的亮度,代码如下library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all; entity pwm_controller is
port(
clk:in std_logic;
pwm_led_in:in std_logic_vector(13 downto 0);
pwm_led_out:out std_logic
);
end pwm_controller; architecture pwm_arch of pwm_controller is signal counter:std_logic_vector(13 downto 0); begin
process(clk)
begin
if(clk'event and clk = '1') then
if(counter >= pwm_led_in) then
pwm_led_out<= '0';
else
pwm_led_out<= '1';
end if;
counter <= counter + 1;
end if;
end process;
end pwm_arch;
Part 0.1.2 软件设计
一些基本工具以及按键、显示器驱动实现
显示器驱动
LCD显示屏初始化
void LCD_init() {
//************* Reset LCD Driver ****************//
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RESET_BASE, 1);
delay_ms(200);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RESET_BASE, 0);
delay_ms(200);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RESET_BASE, 1);
delay_ms(10);
//************* Start Initial Sequence **********//
//剩余参数配置见源代码,这里不予展示
}LCD初始化可以直接利用芯片厂商提供的代码,或者参考芯片资料中的参数配置自行完成。
LCD显示驱动
查阅
ILI9481芯片手册,可以将发送一次指令和内容打包成Index与cmd两个函数。这两个函数内容如下:
void LCD_ILI9481_INDEX(unsigned int data) {
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, data);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
}
void LCD_ILI9481_CMD(unsigned int data) {
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, data);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
}发送一个指令的流程为先利用
cmd函数发送指令,再用INDEX函数发送指令内容。再将LCD显示一个像素的图像打包为
set_addr和send_data两个步骤,先通过set_addr发送像素地址,再用send_data发送像素颜色信息。send_addr的时序可以通过查阅芯片手册来得知,其代码如下:void set_addr(unsigned int x, unsigned int y){
LCD_ILI9481_CMD(0x002b);
LCD_ILI9481_INDEX(x >> 8);
LCD_ILI9481_INDEX(x & 0x00ff);
LCD_ILI9481_INDEX(0x0001);
LCD_ILI9481_INDEX(0x00df); LCD_ILI9481_CMD(0x002a);
LCD_ILI9481_INDEX(y >> 8);
LCD_ILI9481_INDEX(y & 0x00ff);
LCD_ILI9481_INDEX(0x0001);
LCD_ILI9481_INDEX(0x003f); LCD_ILI9481_CMD(0x002c);
}同样,可以写出
send_data如下:void send_data(unsigned int data) {
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, data);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
}LCD显示工具
ascii码显示工具(中文显示工具原理相同),利用
lcd_buffer传参数,字母数据保存在word_libcvoid display_ascii(unsigned int x, unsigned int y, unsigned int w_color,
unsigned int b_color) {
unsigned int i, j, k = 0;
unsigned char str;
unsigned int OffSet, z; while (1) {
if (lcd_buffer[k] == 0) {
set_addr(0, 0);
return;
}
z = lcd_buffer[k];
//每个字符在wordlib中用11
OffSet = z * 11;
//显示一个字符 该字符的像素大小为
for (i = 0; i < 11; i++) {
//读取字符表示中的一个字符的一行
str = word_lib[OffSet + i];
for (j = 0; j < 8; j++) {
//设置显示像素点的相对左边
set_addr(x + j, y - i);
//如果是要显示的话,就显示前景颜色
if (str & 0x80) {
send_data(w_color);
} else {
//如果是不显示的话,显示背景颜色
send_data(b_color);
}
str <<= 1;
}
}
x += 8;
k++;
}
}通过如下方式利用该工具
sprintf((char *)lcd_buffer, "CH1 Freq:");
display_ascii(8, 55, 0x0000, MENU_FULL_COLOR);图片显示则利用如上所诉的
set_addr与send_data完成,欢迎界面显示函数如下(图像利用工具转换后放在welcome数组之中)
void display_Welcome() {
unsigned int i, j, data;
unsigned long k = 0;
//设置初始位置
set_addr(0, 0);
//显示欢迎页,先输出一列再输出一行
for (i = 0; i < 480; i++) {
for (j = 0; j < 320; j++) {
data = welcome[k++];
data = data + (welcome[k++] << 8);
send_data(data);
}
}
}其余显示函数原理如上,不再赘述。
中断处理
时钟中断在此版本中暂时用于处理背光,中断的申请与定义可见各NIOS教程,处理函数如下
void timer(void* context) {
IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_BASE, 0);
IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_BASE, 0x0b); //控制LCD的背光灯
if (LED_PWM_DATA <= 130) {
LED_PWM_DATA += 1;
IOWR_ALTERA_AVALON_PIO_DATA(PWM_LED_BASE, LED_PWM_DATA);
}
IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_BASE, 0x07);
}按键中断则是
SPI总线来读取按键值void KeyListener(void* context) {
KEY_IS_DOWN = !KEY_IS_DOWN;
unsigned char i = 0;
for (i = 0; i < 8; i++) {
send_KEY(((0xfeff << i) >> 8) & 0xff);
if (IORD_ALTERA_AVALON_PIO_DATA(KEY_PORT_BASE) != 0x03) {
if (IORD_ALTERA_AVALON_PIO_DATA(KEY_PORT_BASE) == 1) {
switch (i) {
case 0:
KEY_DATA = 8;
break;
//...
//见源代码 省去
}
} else if (IORD_ALTERA_AVALON_PIO_DATA(KEY_PORT_BASE) == 2) {
switch (i) {
case 0:
KEY_DATA = 0;
break;
//...
//见源代码 省去
}
}
break;
}
}
send_KEY(0x00);
if(KEY_IS_DOWN == 0){
sprintf(lcd_buffer,"keytest");
display_ascii(417,95,0x0000,0xEF78);
sprintf(lcd_buffer,"%2d",KEY_DATA);
display_ascii(417,80,0x0000,0xEF78);
}
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_PORT_BASE, 0x0000);
}
SPI总线的驱动send_key见下void send_KEY(unsigned char data) {
unsigned char u;
IOWR_ALTERA_AVALON_PIO_DATA(SPI_LE_K_BASE, 0);
//串行发送j的数据,通过移位发送j的数据
for (u = 0; u < 8; u++) {
if (data & 0x80) {
IOWR_ALTERA_AVALON_PIO_DATA(SPI_DATA_BASE, 1);
} else {
IOWR_ALTERA_AVALON_PIO_DATA(SPI_DATA_BASE, 0);
} IOWR_ALTERA_AVALON_PIO_DATA(SPI_CLK_BASE, 1); IOWR_ALTERA_AVALON_PIO_DATA(SPI_CLK_BASE, 0); data <<= 1;
//左移发送信号
}
IOWR_ALTERA_AVALON_PIO_DATA(SPI_LE_K_BASE, 1);
}
工具类
工具类主要提供了delay如下
void delay_ms(unsigned int i) {
unsigned int j, k;
for (j = 0; j < i; j++)
for (k = 0; k < 1000; k++);
}
void delay_us(unsigned int i) {
unsigned int j;
for (j = 0; j < i; j++);
}
按照示波器运行流程的代码描述
主函数
#include <stdio.h> #include "../inc/init.h" int main() {
printf("OSC SYSTEM INIT!\n");
SYSTEM_init(); //初始化系统,显示载入界面
printf("SYSTEM INIT FINISHED!\n"); printf("INTERFACE INIT!\n");
INTERFACE_init(); //初始化界面,显示示波器主界面
printf("INTERFACE INIT FINISHED"); while (1) {
//主循环,处理中断,更新界面
}
return 0;
}主函数放在
..\main\main.c下,主要是用于初始化系统,初始化界面,运行时维护界面。初始化系统,显示载入画面
void SYSTEM_init() {
LCD_init(); //初始化显示屏
display_Welcome(); //显示欢迎界面
//初始化中断服务
alt_irq_init(ALT_IRQ_BASE);
KEY_init(); //初始化按键中断
TIMER_init(); //初始化按键中断
//初始化AD模块 (未完成)
delay_ms(5000);
}初始化界面,显示示波器主界面
void INTERFACE_init() {
display_background(); //显示主界面背景
display_area(); //显示波形显示区域
display_menu();
display_rightbox();
display_parabar();
display_toolbar();
}利用上述显示驱动,将界面显示出来。
Part 0.1.F V0.1版本示意
视频演示:http://v.youku.com/v_show/id_XMTgxMjg1ODYzNg==.html
遇到问题解决方案
无法烧录,提示system_ID有问题
遇到这个情况是由于BSP改位置或者BSP没有更新,所以在BSP工程下右键NIOS II子菜单下BSP Editor更改BSP位置,最后Generate BSP即可解决。
基于NIOS-II的示波器:PART1 按键&显示屏驱动&界面的更多相关文章
- 【推荐图书】+ 基于Nios II的嵌入式SoPC系统设计与Verilog开发实例+C#入门经典等
[推荐图书]+ 基于Nios II的嵌入式SoPC系统设计与Verilog开发实例+C#入门经典等 3赞 发表于 2016/7/4 21:14:12 阅读(1921) 评论(3) 初次接触FPGA,到 ...
- 基于NIOS II的双端口CAN通信回环测试
基于NIOS II的双端口CAN通信回环测试 小梅哥编写,未经授权,严禁用于任何商业用途 说明:本稿件为初稿,如果大家在使用的过程中有什么疑问或者补充,或者需要本文中所述工程源文件,欢迎以邮件形式发送 ...
- FPGA回忆记事(一):基于Nios II的LED实验
实验一:基于Nios II的LED实验 一. 创建Quartus II工程 1.打开Quartus II环境.开始->程序->Altera->Quartus II 9.1. 2 ...
- Nios II的Boot过程分析
目录 1 概述....................................................................... 1 2 几种常见的 ...
- DE1-SOC开发板上搭建NIOS II处理器运行UCOS II
DE1-SOC开发板上搭建NIOS II处理器运行UCOS II 今天在DE1-SOC的开发板上搭建NIOS II软核运行了UCOS II,整个开发过程比较繁琐,稍微有一步做的不对,就会导致整个过 ...
- 【小梅哥SOPC学习笔记】NIOS II处理器运行UC/OS II
SOPC开发流程之NIOS II 处理器运行 UC/OS II 这里以在芯航线FPGA学习套件的核心板上搭建 NIOS II 软核并运行 UCOS II操作系统为例介绍SOPC的开发流程. 第一步:建 ...
- [置顶]
基于FPGA的VGA简易显存设计&NIOS ii软核接入
项目简介 本项目基于Altera公司的Cyclone IV型芯片,利用NIOS II软核,2-port RAM与时序控制模块,实现64*48分辨率的显存(再大的显存板载资源m9k不够用) 实现效果如下 ...
- NIOS ii 流水灯
为了做项目的前期验证工作,实验室购买了某开发板,下面是基于该板子的实现过程.作为笔记记录,供入门者参考. 1:创建一个Quartus II的工程 next选择器件,然后finish.我的器件是cycl ...
- NIOS II开发备忘录
大概有一年没做NIOS II的开发了,回想上一次做NIOS II还是去年做毕业设计的时候.那时候做的是基于SOPC的频率特性测试仪,我大约花了2个月的时间,从无到有的学习了NIOS II开发.学习过N ...
随机推荐
- Fluent Validation with Web Api 2
using FluentValidation;using FluentValidation.Attributes;using System;using System.Collections.Gener ...
- Linux操作系统-安装JAVA
首先准备好jdk文件(例如:本地已下载了jdk-6u33-linux-x64.bin),将它上传到路径 “/home/username/” 这个目录的下面 其次按步骤执行: 1.进入到 “/home/ ...
- .Net Core 2.0生态(3):ASP.NET Core 2.0 特性介绍和使用指南
ASP.NET Core 2.0 发布日期:2017年8月14日 ASP.NET团队宣布ASP.NET Core 2.0正式发布,发布Visual Studio 2017 15.3支持ASP.NET ...
- sqlite数据库之简单操作
一 sqlite介绍 Sqlite是一种嵌入式数据库,类似于一个文件系统,是跟程序在一起的.跟mysql等数据库程序跟数据分离是不一样的. 应用场景:常用于保存本地配置,类似于本地文件系统,因此他内嵌 ...
- Velocity.js的使用
前面的话 Velocity是一款优秀的JS动画库,完全可以作为jQuery的animate的替代品.需要动画功能时,使用Velocity是一个好选择.本文将详细介绍Velocity.js的使用 概述 ...
- 免费的Lucene 原理与代码分析完整版下载
Lucene是一个基于Java的高效的全文检索库.那么什么是全文检索,为什么需要全文检索?目前人们生活中出现的数据总的来说分为两类:结构化数据和非结构化数据.很容易理解,结构化数据是有固定格式和结构的 ...
- 关于curl / curl_multi的一些实验
几天没写了,主要都是自己的学习过程,贴一下curl / curl_multi_exec的一些代码,mark一下. <?php /** * Created by PhpStorm. * User: ...
- Random问题
Unity添加C#脚本,打不出来Random.Next,原因是Random自动引用了UnityEngine命名空间,在使用Random的时候要要这么写:System.Random ran=new Ra ...
- 【Ubuntu 16】深入Ubuntu文件系统
Ubuntu文件系统的设计目的就是把文件有序地组织在一起,提供一个从逻辑上组织文件的文件系统.除了文件的组织外,文件安全也是文件系统的设计要点,所以文件的访问权限是文件系统不可缺少的组成部分 Ubun ...
- 【Weblogic】linux下weblogic新建domain(入门教程)
找到weblogic下的/common/bin目录,/home/weblogic/Oracle/Middleware/wlserver_10.3/common/bin ./config.sh -mod ...