准备资料
4 [笔记].如何使用Nios II的中断:PIO中断与定时器中断
操作步骤
步骤1 将ADS7843的驱动文件夹加入APP路径中
步骤2 编写ADS7843的驱动
我们先看下触摸屏芯片采样的坐标与TFT-LCD显示的坐标的区别和联系。图中的TFT-LCD方向为所定义方向,亦即
#define ID_AM 110
其XY坐标与ADS7843采样之坐标翻了。故ADS7843采样及滤波之后,需要把XY坐标翻回来。此外我们可以看到TFT-LCD显示区域是触摸屏采样芯片采样区域的子集,因此如若将程序移植到你的平台上,请坐相应的坐标校准动作。这和我们的触摸屏手机的校准功能是类似的的。
废话不多说,直接贴代码,有什么不明白的地方,请给我留言。
代码2.1 ads7843.h
#ifndef ADS7843_H_
#define ADS7843_H_
#include "my_types.h"
#include "my_regs.h"
#define CHX 0x90
#define CHY 0xD0
void ads_SPIStart(void);
void ads_SPIWrite(u8 cmd);
u16 ads_SPIRead(void);
bool ads_ReadXY(void);
bool ads_GetXY(void);
u8 *intostr(u16 n);
#endif /* ADS7843_H_ */
代码2.2 ads7843.c
#include "ads7843.h"
#include <unistd.h>
// 全局变量,用以储存坐标信息
u16 X=0, Y=0;
// SPI开始状态
void ads_SPIStart(void)
{
ads_CLK=0;
ads_nCS=1;
ads_DIN=1;
ads_CLK=1;
ads_nCS=0;
}
// SPI写一个byte
void ads_SPIWrite(u8 cmd)
{
u8 i;
ads_CLK=0;
for(i=0; i<8; i++) // 上升沿有效
{
ads_DIN = (cmd >> (7-i)) & 0x1; // MSB在前,LSB在后
ads_CLK=0; usleep(1);
ads_CLK=1; usleep(1);
}
}
// SPI读12个bit
u16 ads_SPIRead(void)
{
u8 i;
u16 temp=0;
for(i=0; i<12; i++) // 下降沿有效
{
temp<<=1;
ads_CLK=1; usleep(1);
ads_CLK=0; usleep(1);
if(ads_DOUT) temp++;
}
return temp;
}
// 读取ADS7843采集到X、Y值
// 返回:超出屏幕范围,则返回0
bool ads_ReadXY(void)
{
ads_SPIStart();
ads_SPIWrite(CHX);
ads_CLK=1; usleep(1);
ads_CLK=0; usleep(1);
X = ads_SPIRead();
ads_SPIWrite(CHY);
ads_CLK=1; usleep(1);
ads_CLK=0; usleep(1);
Y = ads_SPIRead();
ads_nCS=1;
if((X>350 && X<3800) && (Y>300 && Y<3800)) // 根据自己的屏自行矫正
return 1; // 读数成功(范围限制)
else
return 0; // 读数失败
}
// 处理从ADS7843读取的X、Y值,然后互换
#define SAMP_CNT 4
#define SAMP_CNT_DIV2 2
bool ads_GetXY(void)
{
u8 i, j, k, min;
u16 temp;
u16 tempXY[2][SAMP_CNT], XY[2];
// 采样
for(i=0; i<SAMP_CNT; i++)
{
if(ads_ReadXY())
{
tempXY[0][i] = X;
tempXY[1][i] = Y;
}
}
// 滤波
for(k=0; k<2; k++)
{ // 降序排列
for(i=0; i<SAMP_CNT-1; i++)
{
min=i;
for (j=i+1; j<SAMP_CNT; j++)
{
if (tempXY[k][min] > tempXY[k][j]) min=j;
}
temp = tempXY[k][i];
tempXY[k][i] = tempXY[k][min];
tempXY[k][min] = temp;
}
// 设定阈值
if((tempXY[k][SAMP_CNT_DIV2]-tempXY[k][SAMP_CNT_DIV2-1]) > 5)
return 0;
// 求中间值的均值
XY[k] = (tempXY[k][SAMP_CNT_DIV2]+tempXY[k][SAMP_CNT_DIV2-1]) / 2;
}
// 矫正坐标
Y = ((XY[0]-350)/11);
X = ((XY[1]-400)/14);
return 1;
}
// 整型转字符串(显示X、Y坐标,3个ASCII码)
u8 *intostr(u16 n)
{
u8 *p;
static u8 buf[3];
p = &buf[3];
*p = (n/100) - ((n/1000)*10)+48;
*(p+1) = (n/10) - ((n/100)*10) +48;
*(p+2) = n- ((n/10) *10) +48;
*(p+3) = 0;
return p;
}
步骤3 触摸屏驱动测试
代码 main.c
#include <unistd.h> // usleep()
#include "my_types.h" // 数据类型
#include "my_regs.h" // 自定义引脚及寄存器映射
#include "debug.h" // debug
#include "ili932x.h" // ILI9325
#include "ads7843.h" // ADS7843
#include "sd_card.h" // SD Card
#include "system.h" // 系统
#include "altera_avalon_pio_regs.h" // PIO,ads_nIRQ
#include "sys/alt_irq.h" // 中断
// 变量申明
extern u16 X, Y;
// 函数申明
vu16 nirq_isr_context; // 定义全局变量以储存isr_context指针
void nIRQ_Initial(void);
void nIRQ_ISR(void* isr_context);
void ResetTouch(void);
// 调试信息显示开关
#define ENABLE_APP_DEBUG // turn on debug message
#ifdef ENABLE_APP_DEBUG
#define APP_DEBUG(x) DEBUG(x)
#else
#define APP_DEBUG(x)
#endif
// nIRQ中断初始化
void nIRQ_Initial(void)
{
// 改写timer_isr_context指针以匹配alt_irq_register()函数原型
void* isr_context_ptr = (void*) &nirq_isr_context;
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(ADS_NIRQ_BASE, 1); // 使能中断
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(ADS_NIRQ_BASE, 1); // 清中断边沿捕获寄存器
// 注册ISR
alt_ic_isr_register(
ADS_NIRQ_IRQ_INTERRUPT_CONTROLLER_ID, // 中断控制器标号,从system.h复制
ADS_NIRQ_IRQ, // 硬件中断号,从system.h复制
nIRQ_ISR, // 中断服务子函数
isr_context_ptr, // 指向与设备驱动实例相关的数据结构体
0x0); // flags,保留未用
}
// 中断服务子函数
void nIRQ_ISR(void* isr_context)
{
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(ADS_NIRQ_BASE, 1); // 清中断边沿捕获寄存器
if(ads_GetXY())
{
if((X>190 && X<240 && Y>300 && Y<320)) ResetTouch();
else
{
ili_PutString(34, 289, intostr(X), Blue, White);
ili_PutString(34, 305, intostr(Y), Blue, White);
ili_PlotBigPoint(X, Y, Red);
}
}
}
//
void ResetTouch(void)
{
ili_ClearScreen(White);
ili_PutString(190, 305, (u8 *)("Clear"), Blue, White);
ili_PutString(10, 289, (u8 *)("X: 0"), Blue, White);
ili_PutString(10, 305, (u8 *)("Y: 0"), Blue, White);
}
int main(void)
{
ili_Initial();
nIRQ_Initial();
ResetTouch();
while(1);
return 0;
}
第34~47行,初始化nIRQ引脚下降沿中断;第51~65行,编写nIRQ中断函数。其他就不多说了。
测试效果如下:
源码下载
目录
1 [原创][连载].基于SOPC的简易数码相框 - Quartus II部分(硬件部分)
2 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- 配置工作
3 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- SD卡(SPI模式)驱动
4 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- TFT-LCD(控制器为ILI9325)驱动
5 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- 从SD卡内读取图片文件,然后显示在TFT-LCD上
6 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- 优化工作
7 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- ADS7843触摸屏驱动测试