JZ2440 ADC和触摸屏学习笔记

裸机系列代码地址:链接:http://pan.baidu.com/s/1pLHOd0v 密码:4x5s

S3C2440的CMOS模数转换器可以接收8个通道的模拟信号输入,并将它们转换成10位的二进制数据

S3C2440的触摸屏接口向外提供4个控制引脚(XP,XM,YP,YM)与触摸屏的直接相连。S3C2440的ADC和触摸屏机构图如下所示
JZ2440 ADC和触摸屏学习笔记_第1张图片
图中有两个中断信号:INT_ADC,INT_TC,前者表示A/D转换已经完成,后者表示触摸屏被按下了,或者弹起了。
在使用触摸屏是AIN[7:4]被用来和触摸屏相连,所以只有剩下的AIN[3:0]可以作为普通A/D转换通道用,不使用触摸屏时AIN[7:0]均可用作普通A/D转换通道
ADC的启动方式有两种:1、手工启动,第一次转换是使用
     2、读结果时就自动启动下一次转换,除第一次转换外使用
也有两种方法得知转换结束:1、查询状态位
    2、转换结束时发出中断INT_ADC_S
下面看一看ADC和触摸屏使用时主要使用的寄存器
ADCCON寄存器格式
[15]:只读,A/D转换结束标志。0=正在转换,1=转换结束
[14]:决定A/D转换器的时钟是否使用预分频。0=不使用,1=使用。通常情况需要使用预分频
[13:6]:预分频系数PRSCVL,取值0~255,A/D时钟=PCLK/(PRSCVL)。注意:A/D时钟必须小于PCLK的1/5
[5:3]:选择进行AD转换的通道
[2]:选择静态模式,0=正常模式,1=静态模式
[1]:读数据时是否启动下一次转换。0=不启动,1=启动
[0]:启动A/D转换。0=无作用,1=启动(真正转换开始时,此位被置0)

ADCDAT0寄存器格式
[15]:对于触摸屏,使用“等待中断模式”时,0=触摸屏被按下,1=触摸屏没有被按下
[14]:决定是否使用自动(连续)X/Y轴坐标转换模式
[13:12]:手动X/Y轴坐标转换模式
[11:10]:保留
[9:0]:x轴坐标转换数值

ADCDAT1数据格式和ADCDAT0相似

ADCTSC寄存器格式
[8]:表示检测的中断类型。0=触点按下中断,1=触点松开中断
[7]:0=YM驱动禁止(高阻),1=YM驱动使能(接地)
[6]:0=YP驱动禁止(接外部电压),1=YP驱动使能(接模拟输入)
[5]:0=XM驱动禁止(高阻),1=XM驱动使能(接地)
[4]:0=XP驱动禁止(接外部电压),1=XP驱动使能(接模拟输入)
[3]:PULL_UP,XP上拉使能,0=禁止上拉,1=使能上拉
[2]:AUTO_PST,是否使用自动(连续)X/Y轴坐标转换模式,0=普通模式,1=自动转换模式
[1:0]:手动量测X,Y轴坐标。00=无操作模式,01=量测x轴,10=量测y轴,11=等待中断模式

等待中断模式,如下为等待中断模式的触摸屏等效电路图,ADCTSC寄存器的设置参考此图
JZ2440 ADC和触摸屏学习笔记_第2张图片
图中,S4,S5闭合,S1,S2,S3断开,即YM接地,XP上拉,XP作为模拟输入,YP作为模拟输入,XM高阻
从图中可知,设置ADCTSC寄存器为0xd3即可令触摸屏处于等待中断模式,这时,它在等待触摸屏被按下或是等待弹起。触摸屏
按下时产生INT_TC中断,弹起时亦产生此中断。

自动(连续)X/Y轴坐标转换模式
设置ADCTSC寄存器为0x0c进入此模式,触摸屏控制器就会自动转换触点的x,y坐标值,并分别写入ADCDAT0和ADCDAT1寄存器中
然后发出INT_ADC中断

对于普通转换模式,分离的x/y轴坐标转换模式,自动(连续)X/Y轴坐标转换模式,都可以通过ADCDLY寄存器来设置采样的延时时间
JZ2440 ADC和触摸屏学习笔记_第3张图片
触摸屏的程序流程图和控制的状态转移图如下所示
JZ2440 ADC和触摸屏学习笔记_第4张图片

下面是一个触摸屏的实例程序

Makefile 文件

objs:= head.o init.o main.o irq.o
adcts.bin: $(objs) 
	arm-linux-ld -Tadc_ts.lds -o adcts_elf $^
	arm-linux-objcopy -O binary -S adcts_elf $@
	arm-linux-objdump -D -m arm adcts_elf > adcts.dis
%.o:%.c 
	arm-linux-gcc -Wall -O2 -c -o $@ $<
%.o:%.s 
	arm-linux-gcc -Wall -O2 -c -o $@ $< 	
clean:
	rm -f adcts_elf adcts.dis adcts.bin *.o 
链接文件
SECTIONS {
    . = 0x30000000;
    .text          :   { *(.text) }
    .rodata ALIGN(4) : {*(.rodata)} 
    .data ALIGN(4) : { *(.data) }
    .bss ALIGN(4)  : { *(.bss)  *(COMMON) }
}
head.S

.text
.global _start
_start:
	b reset 
HandleUndef:
	b HandleUndef

HandlerSWI:
	b HandlerSWI 

HandlePrefetchAbort:
	b HandlePrefetchAbort

HandleDataAbort:
	b HandleDataAbort

HandleNotUsed:
	b HandleNotUsed

    b HandleIRQ           /*中断向量表的位置必须固定,即 b HandleIRQ运行位置必须在0x18处*/

HandleFIQ:
	b HandleFIQ

reset:
	ldr sp,=4096                     /*设置C函数使用的栈*/
	bl disable_watch_dog
	msr cpsr_c,#0xd2     /*进入中断模式*/ 
	ldr sp,=3072         /*设置中断模式栈指针*/

	msr cpsr_c,#0xd3     /*进入系统模式*/
	ldr sp,=4096 		 /*设置系统模式栈指针*/	
	msr cpsr_c,#0x5f     /*开IRQ中断,这之后程序可以响应中断*/

	bl init_clock                    /*设置系统时钟,使得uart使用PCLK为50MHZ*/
	bl memsetup                      /*初始化存储控制器使得SDRAM可用*/
	bl copy_steppingstone_to_sdram   /*将代码复制到SDRAM中*/
	ldr pc,=on_sdram                 /*地址相关代码,从这里开始程序在SDRAM中运行*/
	
on_sdram:
	ldr sp,=0x34000000                /*设置代码在SDRAM中运行时的栈*/
	bl init_uart0                     /*初始化串口0*/
	bl main 
	bl halt_loop

halt_loop:
	b halt_loop 

HandleIRQ:
	sub lr,lr,#4
	stmdb sp!,{r0-r12,lr} 

	ldr lr,=int_return 
	ldr pc,=EINT_Handle

int_return:
	ldmia sp!,{r0-r12,pc}^
init.c

#include "s3c2440.h"

void disable_watch_dog(void)
{
	WTCON = 0x53000000;
}

/*注意这里必须用这种方式,用数组循环赋值的方式不可取*/
void memsetup(void)
{
	volatile unsigned long *p = (volatile unsigned long *)0x48000000;

	/* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值
     * 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到
     * SDRAM之前就可以在steppingstone中运行
     */
    /* 存储控制器13个寄存器的值 */
    p[0] = 0x22011110;     //BWSCON
    p[1] = 0x00000700;     //BANKCON0
    p[2] = 0x00000700;     //BANKCON1
    p[3] = 0x00000700;     //BANKCON2
    p[4] = 0x00000700;     //BANKCON3  
    p[5] = 0x00000700;     //BANKCON4
    p[6] = 0x00000700;     //BANKCON5
    p[7] = 0x00018005;     //BANKCON6
    p[8] = 0x00018005;     //BANKCON7
    
    /* REFRESH,
     * HCLK=12MHz:  0x008C07A3,
     * HCLK=100MHz: 0x008C04F4
     */ 
    p[9]  = 0x008C04F4;
    p[10] = 0x000000B1;     //BANKSIZE
    p[11] = 0x00000030;     //MRSRB6
    p[12] = 0x00000030;     //MRSRB7

}

void copy_steppingstone_to_sdram(void)
{
	unsigned int *pdest = (unsigned int *)0x30000000;
	unsigned int *psrc  = (unsigned int *)0x00000000;

	while(psrc<(unsigned int *)4096)
		{
			*pdest = *psrc;
			pdest++;
			psrc++;
		}

}

void init_clock(void)
{
	#define MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
	CLKDIVN = 0x03;
			__asm__(
    "mrc    p15, 0, r1, c1, c0, 0\n"        /* 读出控制寄存器 */ 
    "orr    r1, r1, #0xc0000000\n"          /* 设置为“asynchronous bus mode” */
    "mcr    p15, 0, r1, c1, c0, 0\n"        /* 写入控制寄存器 */
    );
	MPLLCON = MPLL_200MHZ;
}

void init_uart0(void)
{
	GPHCON = 0xa0;      /*GPH2,GPH3用作TXD0,RXD0*/
	GPHUP  = 0x0c;      /*GPH2,GPH3内部上拉*/

	#define UART_PCLK   50000000
	#define baurd       115200
	#define UART_BRD    ((UART_PCLK/(baurd*16)) -1 )

	ULCON0 = 0x03;      /*数据位数为8,一个停止位,无奇偶校验*/
	UCON0 = 0x05;       /*查询方式,UART时钟源为PCLK*/
	UFCON0 = 0x00;      /*不使用FIFO*/
	UMCON0 = 0x00;      /*不使用流控*/
	UBRDIV0 = UART_BRD; /*波特率为115200*/
}
irq.c
#include "s3c2440.h"

#define TXD0READY (1<<2)
#define RXD0READY (1)
#define ADC_START (1 << 0)
#define PRESCALE_EN  (1 << 14)
#define PRSCVL(x)    ((x) << 6)

void putcc(char c)
{
	while( !(UTRSTAT0 & TXD0READY));
		UTXH0 = c;
}

unsigned char getcc(void)
{
	while(!(UTRSTAT0 & 1));

	return URXH0;
}

void putstring(char *p)
{
	while(*p != '\0')
		{
			putcc(*p);
			p++;
		}
}

static void isr_tc(void)
{
	if(ADCDAT0 & 0x8000)
		{
			putstring("stylus up\n\r");
			ADCTSC = 0xd3;          /*进入等待中断模式,检测触电按下*/
		}
	else
		{
			putstring("stylus down\n\r");
			ADCTSC = 0x0c;          /*进入自动X/Y连续转换模式*/
			ADCCON |= ADC_START;    /*开启ADC转换*/
		}

	/*清除中断*/
	SUBSRCPND |= BIT_SUB_TC;
	SRCPND |= BIT_ADC;
	INTPND |= BIT_ADC;
}

static void isr_adc(void)
{
	int x,y;
	x = (int)(ADCDAT0 & 0x3ff);
	y = (int)(ADCDAT1 & 0x3ff);

	char ptx[4]={'\0','\0','\0','\0'};
	char pty[4]={'\0','\0','\0','\0'};

	ptx[0]=x/100+'0';
	ptx[1]=(x%100)/10+'0';
	ptx[2]=x%10+'0';

	pty[0]=y/100+'0';
	pty[1]=(y%100)/10+'0';
	pty[2]=y%10+'0';

	putstring(ptx);
	putstring("\n\r");
	putstring(pty);
	putstring("\n\r");

	ADCTSC = 0x1d3;;             /*进入等待中断模式,检测触电松开*/

	/*清除中断*/
	SUBSRCPND |= BIT_SUB_ADC;
	SRCPND |= BIT_ADC;
	INTPND |= BIT_ADC;
}


void EINT_Handle(void)
{
	if(SUBSRCPND & BIT_SUB_TC)             /*如果是TC中断,则进入TC中断的处理函数*/
		isr_tc();
	if(SUBSRCPND & BIT_SUB_ADC)            /*如果是ADC中断,则进入ADC中断的处理函数*/
		isr_adc();
}

void Test_Ts(void)
{
    INTMSK &= ~BIT_ADC;          // 开启ADC总中断
    INTSUBMSK &= ~(BIT_SUB_TC);  // 开启INT_TC中断,即触摸屏被按下或松开时产生中断
    INTSUBMSK &= ~(BIT_SUB_ADC); // 开启INT_ADC中断,即A/D转换结束时产生中断
    INTMOD &= ~BIT_ADC;
    
    // 使能预分频功能,设置A/D转换器的时钟 = PCLK/(49+1)
    ADCCON = PRESCALE_EN | PRSCVL(49);

    /* 采样延时时间 = (1/3.6864M)*50000 = 13.56ms
     * 即按下触摸屏后,再过13.56ms才采样
     */
    ADCDLY = 50000;
	ADCTSC = 0xd3;                   /* 进入"等待中断模式",等待触摸屏被按下 */
}
main.c

#include "s3c2440.h"

extern void Test_Ts(void);
extern void putstring(char *);
int main()
{
	Test_Ts();
	while(1);
	return 0;
}






你可能感兴趣的:(嵌入式)