990 likes | 1.12k Views
5.4 人机接口电路设计及编程. 5.4.1 键盘电路设计及编程. 1. 电路. 键盘接口电路 如图 5-12 所示 ,板上扩展了一个 4×4 行列式矩阵键盘接口。 该键盘采用中断扫描方式进行工作 , 行线选用 PORTG4~7 输出,列线选用 PORTF5~8 为输入。 行线 接上拉电阻保持高电平,并通过“与”门将输出信号与 MCU 的中断 EXINT0 连接; 列线 接上拉电阻保持高电平。. 2. 编程. (1) I/O 口和中断初始化 ① I/O 引脚设置: rPDATE=0X60;
E N D
1. 电路 键盘接口电路如图5-12所示,板上扩展了一个4×4行列式矩阵键盘接口。 该键盘采用中断扫描方式进行工作,行线选用PORTG4~7输出,列线选用PORTF5~8为输入。 行线接上拉电阻保持高电平,并通过“与”门将输出信号与MCU的中断EXINT0连接; 列线接上拉电阻保持高电平。
2. 编程 (1) I/O口和中断初始化 ① I/O引脚设置: rPDATE=0X60; rPCONF=0x2A; 列线PORTF5~8为输入 rPUPF=0x0; 列线接上拉电阻 rPDATG=0x0; rPCONG=0x55FF; 行线PORTG4~7输出,PORTG0作为EXINT0连接 rPUPG=0x0; 行线接上拉电阻
② 中断初始化 rINTCON=0x5; // 非向量模式,IRQ 允许,FIQ 禁止 rINTMOD=0x0; // 全部IRQ 模式 rINTMSK =~(BIT_GLOBAL|BIT_EINT0); //EXINT0允许, 所有中断屏蔽位允许 pISR_EINT0=(unsigned)keyboard_ISR; //指定中断服务程序
(2) 程序 将行线PORTG4~7输出为低电平,当有键盘按下时,该行线被拉为低电平,使得EXINT0输入也为低电平,MCU产生中断。 中断产生后通过对键盘的行和列进行扫描的方法,可以计算出是哪个键按下,并跳到相应的键盘处理程序中去。
void keyboard_ISR(void) { char x,y,xrecord,yrecord,temp; rI_ISPC=BIT_EINT0; //clear pending_bit Delay(400); //delay 40ms if((rPDATF&0x1E0)==0x1E0) { return 0; //no keyboard press,return }
else { x=1; y=1; xrecord=(~((rPDATF&0x1E0)>>1)); xrecord=xrecord>>4; while(xrecord!=0x1) //judge row { x=x+1; xrecord=xrecord>>1;
if(xrecord==0) { rPDATG=0X0F; // no ,return return 0;} } Delay(200); //delay 20ms rPDATG=0XEF; //input high
while((rPDATF&0x1E0)==0x1E0) { rPDATG=rPDATG<<1; temp=rPDATG; if((temp&0xf0)==0XF0) //noboard press,return { rPDATG=0X0F; return 0;} }
Delay(200); //delay 10ms yrecord=~((rPDATG&0xF0)>>4)&0x0F; while(yrecord!=0x1) // judge line { y=y+1; yrecord=yrecord>>1; if(yrecord==0) { rPDATG=0X0F; //no board press,return return 0;} }
Led_Display(x+(y-1)*4-1); Uart_Printf("%3d",x+(y-1)*4-1); Delay(1200); //delay 40ms rPDATG=0X0F; } }
1. LCD接口信号 EV44B0 II现配有160×240的单色显示屏,4比特单扫描。EV44B0 II将LCD控制信号线连接到JP6上,与LCD模块相连,其原理如图5-13所示。 在LCD模块上,集成了LCD驱动器和专门的电压转换电路,用以驱动LCD屏幕和适配LCD工作电压。LCD连接器的信号定义如表5-4所示。
1. LCD接口信号 EV44B0 II现配有160×240的单色显示屏,4比特单扫描。EV44B0 II将LCD控制信号线连接到JP6上,与LCD模块相连,其原理如图5-13所示。 在LCD模块上,集成了LCD驱动器和专门的电压转换电路,用以驱动LCD屏幕和适配LCD工作电压。LCD连接器的信号定义如表5-4所示。
2. 编程 显示缓冲区与LCD象素对应关系图如图5-14所示。
(1) LCD 初始化程序 通常采用S3C44B0X的PORTC口和PPORTD口作为LCD驱动接口,因此需要设置它们工作在第3功能状态,设置I/O口控制寄存器的语句如下: rPDATC=0x8400; rPCONC=0x5F5FFFFF; rPUPC=0x33ff; //should be enabled rPCOND=0xaaaa; rPUPD=0xff;
LCD初始化程序如下: void Lcd_MonoInit(void) { //160x240 1bit/1pixel LCD #define MVAL_USED 0 rLCDCON1=(0)|(1<<5)|(MVAL_USED<<7) |(0x3<<8)|(0x3<<10)|(CLKVAL_MONO<<12); //disable,4B_SNGL_SCAN,WDLY=8clk,WLH=8clk, rLCDCON2=(LINEVAL)|(HOZVAL<<10)|(10<<21); //LINEBLANK=10
rLCDSADDR1=(0x0<<27)|(((U32)frameBuffer1>>22) <<21)|M5D((U32)frameBuffer1>>1); // monochrome, LCDBANK, LCDBASEU rLCDSADDR2=M5D((((U32)frameBuffer1+(SCR_X SIZE*LCD_YSIZE/8))>>1))|(MVAL<<21)|(1<<29); rLCDSADDR3= (LCD_XSIZE/16)|(((SCR_X SIZE-LCD_XSIZE)/16)<<9); rLCDCON1=(1)|(1<<5)|(MVAL_USED<<7)|(0x3<<8)| (0x3<<10)|(CLKVAL_MONO<<12); //enable,4B_SNGL_SCAN,WDLY=8clk,WLH=8clk, }
(2) LCD 显示程序 LCD 显示程序如下: #define frameBuffer1 0xc400000 extern unsigned char *Buf; void displaylcd(void) { unsigned int *pbuffer,temp_data; int i; pbuffer =(U32*) frameBuffer1;
for(i = 0; i< (4800/4) ;i++) { temp_data = (Buf[i*4+3] << 24) + (Buf[i*4+2] << 16) + (Buf[i*4+1] << 8) +(Buf[i*4]); pbuffer[i] = ~temp_data; Delay(10); } }
(3) LCD 清屏程序 LCD 清屏程序如下: void clrscreen(void) { int i,j; unsigned int *pbuffer; pbuffer =(U32*) frameBuffer1; for (i=0;i<4800/4;i++) { pbuffer[i] =0;//(0x0FFFFFFFF); } }
5.4.3 触摸屏电路设计及编程 1. 触摸屏的工作原理 触摸屏按其工作原理的不同分为表面声波屏、电容屏、电阻屏和红外屏几种。 常见的又数电阻触摸屏。如图5-15 所示,电阻触摸屏的屏体部分是一块与显示器表面非常配合的多层复合薄膜,由一层玻璃或有机玻璃作为基层,表面涂有一层透明的导电层,上面再盖有一层外表面硬化处理、光滑防刮的塑料层,它的内表面也涂有一层透明导电层,在两层导电层之间有许多细小(小于千分之一英寸)的透明隔离点把它们隔开绝缘。
如图5-16所示,当手指或笔触摸屏幕时(图c),平常相互绝缘的两层导电层就在触摸点位置有了一个接触,因其中一面导电层(顶层)接通X 轴方向的5V 均匀电压场(图a),使得检测层(底层)的电压由零变为非零,控制器侦测到这个接通后,进行A/D 转换,并将得到的电压值与5V 相比即可得触摸点的X 轴坐标为(原点在靠近接地点的那端): Xi=Lx*Vi/V(即分压原理)同理得出Y 轴的坐标,这就是所有电阻触摸屏共同的最基本原理。
2.触摸屏电路控制 触摸屏的控制采用专用芯片,专门处理是否有笔或手指按下触摸屏,并在按下时分别给两组电极通电,然后将其对应位置的摸拟电压信号经过A/D 转换送回处理器 .
我们选取 GPG 口与 ADS7843 接口。共运用了 PG2~PG7 口共 6 条口线。你也可以选择其它的 I/O 口,但注意不要与 I/O 口上已经设定的功能(例如串口)相冲突。参考电路图如下:按照下图用导线将两个模块连接起来。如图5-17所示。
3.编程 (1) PCONG 寄存器配置 按照以上电路来设置,PG6和PG5输入,PG4~PG2输出,PG7作为中断EINT7且加内部上拉电阻,初始化语句如下: rPCONG=0x015f; rPUPG &=0x80;
(2) ADS7843编程 ADS7843的控制字如表5-5所示,其中S为数据传输起始标志位,该位必为1。 A2~A0进行通道选择。 MODE用来选择A/D转换的精度,1--选择8位,0--选择12位。 SER/DFR选择参考电压的输入模式。
PD1和PD0选择省电模式:00--为省电模式允许,在两次A/D转换之间掉电,且中断允许;01同00,只是不允许中断;10保留;11禁止省电模式。PD1和PD0选择省电模式:00--为省电模式允许,在两次A/D转换之间掉电,且中断允许;01同00,只是不允许中断;10保留;11禁止省电模式。 A0~A2 用来进行开关切换,如表5-6所示。
我们采用固定参考电压模式,因此 SER/DFR=1。 程序中首先探测 PENIRQ 是否为低电平,如果为高则认为触摸屏没有接触;如果探测到 PENIRQ 为低电平,则认为有接触。 利用软件模拟 DIN、DOUT、DCLK上的 3 线串行传输的时序,将读取 X 坐标数值或 Y 坐标数值的控制字串行送入 ADS7843,并串行读出坐标值。
① 检测 PENIRQ #define TOUCH_MSR_Y 0x9c; //读 Y 轴坐标命令 #define TOUCH_MSR_X 0xdc; //读 X 轴坐标命令 …… if((rPDATG&0x80)==0) //PENIRQ 电平为低 { //TouchState.pressed=1; _State.Pressed=1; //说明已经按下 temp=TOUCH_MSR_X; _State.x=ReadTouch(temp); temp=TOUCH_MSR_Y; _State.y=ReadTouch(temp); …… }
② 送控制字并读取结果子程序 int ReadTouch(unsigned char command) { unsigned char temp,i,ack,j,k; ack=0; //PG7<-PENIRQ,PG6<-BUSY,PG5<-DOUT, PG4->CS,PG3->DCLK,PG2->DIN rPDATG&=0xe7; //cs 置低;dclk 置低 temp=0x80;
for(i=0;i<8;i++) //发送 1 个字节 { if(command&temp) //将控制字分解为位 rPDATG|=0x04; //将 din 置 1 else rPDATG&=0xfb; //将 din 清 0 rPDATG|=0x08; //置高 dclk delay(2); rPDATG&=0xf7; //清除 dclk,1 位送出 delay(2); temp=temp>>1; //移位 }
while((temp=(rPDATG&0x40))==0); 等待 BUSY 变低 rPDATG&=0xdf;//din 清零 //再 1 个时钟以后开始接收数据 rPDATG|=0x08; //置高 dclk delay(2); rPDATG&=0xf7; //清零 dclk delay(2);
for(i=0;i<7;i++)取得前 7 位坐标数据(高位在前) { rPDATG|=0x08; //置高 dclk if(temp=rPDATG&0x20) //取得 din 上的 1 位数据 ack+=1; ack=ack<<1; delay(2); rPDATG&=0xf7; //清零 dclk delay(2); } rPDATG|=0x08; //置高 dclk
if(temp=rPDATG&0x20) //接收最后 1 位 ack+=1; delay(2); rPDATG&=0xf7; //清零 dclk rPDATG|=0x10; //置高 cs return ack; //返回接收结果 }
4.触摸屏与显示器的配合 ADS7843 送回控制器的X 与Y 值仅是对当前触摸点的电压值的A/D 转换值,它不具有实用价值。 这个值的大小不但与触摸屏的分辨率有关,而且也与触摸屏与LCD 贴合的情况有关。而且,LCD 分辨率与触摸屏的分辨率一般来说是不一样,坐标也不一样。 因此,如果想得到体现LCD 坐标的触摸屏位置,还需要在程序中进行转换。
假设LCD 分辨率是320×240,坐标原点在左上角;触摸屏分辨率是900×900,坐标原点在左上角,则转换公式如下: xLCD=[320*(x-x2)/(x1-x2)]; yLCD=[240*(y-y2)/(y1-y2)];
如果坐标原点不一致,比如LCD 坐标原点在右下角,而触摸屏原点在左上角,则还可以进行如下转换: xLCD=320-[320*(x-x2)/(x1-x2)]; yLCD=240-[240*(y-y2)/(y1-y2)]; 最后得到的值,便可以尽可能得使LCD 坐标与触摸屏坐标一致,这样,更具有实际意义。
5.4.4 8段数码管电路设计及编程 1.电路设计 系统使用了一个8段数码LED,如图2-18所示。该数码管是共阳极的,低电平信号使LED点亮。 CPU数据总线DATA(0~7)经74LS573驱动器对数码管进行驱动。其片选信号由CPU的nGCS3信号选通,而8段的内容则由CPU低8位数据线决定。 口地址为0x6000000。
2.编程 8段数码管显示程序如下: void Led_Display(unsigned char data) { unsigned char * ledbuffer = (unsigned char *) 0x6000000 switch(data){ case 0: *ledbuffer=0x12; break; ... case 0xf: *ledbuffer=0x68; break; } }
5.5.1 串行电路接口 串行接口电路如图5-19所示。系统提供两个RS232标准串行接口(DB9),UART0/l可与PC或MODOM进行串行通信。 PORTC10~15分别作为nRTS1、nCTS1、TXD1、RXD1、nRTS0和nCTS0信号,PE1和PE2作为TXD0和RXD0信号。 两个接口则采用两片MAX2322C作为电平转换器。
5.5.2 编程 1. I/O接口配置初始化 对PORTC和PORTE初始化语句如下: rPCONC = 0x0f000000|rPCONC; rPUPC = 0x3000; //设置内部上拉 rPCONE = (rPCONE&0xfc3)|0xeb; rPUPE = 0x6; 2. UART初始化 对 UART 口进行初始化设置程序如下:
static int UartNum=0; void myUart_Init(int whichuart, int baud) //设置串口波特率等初始化工作。 { if(whichuart==0) { UartNum=0; rUFCON0=0x0; //不使用 FIFO rUMCON0=0x0; //不使用自动流控制 rULCON0=0x3; //不采用红外线传输模式,无奇偶校验 位,1 个停止位, //8个数据位
rUCON0=0x245; //发送中断为电平方式,接收中断为 边沿方式,禁止超时 //中断,允许产生错误状态中断,禁止回 送模式,禁止中 //止信号,传输模式为中断请求模式,接 收模式也为中断 //请求模式。 rUBRDIV0=((int)(MCLK/16./baud + 0.5)-1); //根据波特率计算 UBRDIV0 的值 }
else if(whichuart==1) { UartNum=1; rUFCON1=0x0; rUMCON1=0x0; rULCON1=0x3; rUCON1=0x245; rUBRDIV1 = ( (int)(MCLK/16./baud + 0.5) -1 ); } }
3.字符发送程序 #define WrUTXH0(ch)(*(volatile unsigned char*)0xld00020)=(unsigned char)(ch) #define WrUTXH0(ch)(*(volatile unsigned char*)0xld04020)=(unsigned char)(ch) Void myUart_SendByte(char ch) { if(UartNum==0) { if(ch==“\n”) { while(!(rUTRSTAT0&0x2)); //等待,直到发送缓冲区为空 Delay(10); //超级中断的响应速度较慢 WrUTXH0(“\r”); //发送回车符 } while(!(rUTRSTAT0&0x2)); //等待,知道发送缓冲区为空 Delay(10); WrUTXH0(ch); //发送字符 }
else { if(ch==“\n”) { while(!(rUTRSTAT1&0x2)); Delay(10); //因为超级终端响应较慢 rUTXH1=“\r”; } While(!(rUTRSTAT1&0x2)); //等待THR空。 Delay(10); WrUTXH1(ch); } }
字符接受程序 #define RdURXH0()(*(volatile unsigned char*)(0xld00027)) #define RdURXH1()(*(volatile unsigned char*)(0xld04027)) Char Uart_Getch(void) { if(whichUart==0) //串口0 { while(!(rUTRSTAT0&0x1)); //读出接收到的数据(一直到读完) return RdURXH0(); //URXH0:UART0接收缓冲寄存器 } else //串口1 { while(!(rUTRSTAT1&0x1)); //Receive data ready return rURXH1; } }