4 [笔记].如何使用Nios II的中断:PIO中断与定时器中断
我们先看下触摸屏芯片采样的坐标与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; }
代码 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触摸屏驱动测试