Wei Dongshan ARM Bare Metal and uboot Encyclopedia (1st Enhanced Edition) Study Notes 18-Lesson 018_ADC and Touch Screen_Sections 006~008_Touch Screen Programming_ADC Interrupt

Continue to write based on the code in the previous section

Section 006-Touch screen programming _ADC interrupt (read XY coordinates)

For this program: When it is detected that the touch screen is pressed, it is necessary to start ADC interrupt to read the xy position coordinates.

//相对于上一节代码本函数修改了ADCDLY寄存器值
//因为之前配置值过小,触摸屏的电压输出尚未稳定,所以需要增大自按下触摸笔到产生触摸屏中断的时间
void adc_ts_reg_init(void)
{
    
    
	...
	/*  按下触摸屏, 延时一会再发出TC中断
	 *  延时时间 = ADCDLY * 晶振周期 = ADCDLY * 1 / 12000000 = 5ms
	 */
	ADCDLY = 60000;	
}

//中断服务程序
void AdcTsIntHandle(int irq)
{
    
    
	if (SUBSRCPND & (1<<TC_INT_BIT))  /* 如果是触摸屏中断 */
		Isr_Tc();

	if (SUBSRCPND & (1<<ADC_INT_BIT))  /* ADC中断 */
		Isr_Adc();
	SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT);
}
//***********************************
//中断服务程序调用子函数1
void Isr_Adc(void)
{
    
    
	int x = ADCDAT0;//x方向位置坐标
	int y = ADCDAT1;//y方向位置坐标

	if (!(x & (1<<15))) /* 如果仍然按下才打印 */
	{
    
    
		x &= 0x3ff;
		y &= 0x3ff;
		
		printf("x = %08d, y = %08d\n\r", x, y);
	}
	//此时已经按下,需要等待触摸笔松开
	enter_wait_pen_up_mode();
}

//***********************************
//中断服务程序调用子函数2
void Isr_Tc(void)
{
    
    
	if (ADCDAT0 & (1<<15))
	{
    
    
		//printf("pen up\n\r");
		enter_wait_pen_down_mode();
	}
	else	
	{
    
    
		//printf("pen down\n\r");

		/* 进入"自动测量"模式 */
		enter_auto_measure_mode();

		/* 启动ADC */
		ADCCON |= (1<<0);//开始ADC转换
	}
}
/* 进入"自动测量"模式 */
/* ADCTSC's bits */
#define WAIT_PEN_DOWN    (0<<8)
#define WAIT_PEN_UP      (1<<8)

#define YM_ENABLE        (1<<7)
#define YM_DISABLE       (0<<7)

#define YP_ENABLE        (0<<6)
#define YP_DISABLE       (1<<6)

#define XM_ENABLE        (1<<5)
#define XM_DISABLE       (0<<5)

#define XP_ENABLE        (0<<4)
#define XP_DISABLE       (1<<4)

#define PULLUP_ENABLE    (0<<3)
#define PULLUP_DISABLE   (1<<3)

#define AUTO_PST         (1<<2)//自动顺序转换xy坐标

#define WAIT_INT_MODE    (0b11)//等待中断
#define NO_OPR_MODE      (0)

void enter_auto_measure_mode(void)
{
    
    
	ADCTSC = AUTO_PST | NO_OPR_MODE;
}


Section 007-Touch Screen Programming_Timer Interrupt

  1. The program coding idea in the previous section: when the touch screen is pressed -> touch screen is pressed interrupt -> configure start ADC measurement interrupt -> wait for the touch screen to release
  2. Disadvantages: If the touch screen has been pressed down and it has been stuck waiting for the touch screen to be released, it will not drive the adc for data conversion all the time.
  3. Solution: Add timer interrupt, if the touch screen is pressed, ADC conversion and conversion interrupt will be started regularly.

1 timer interrupt function improvement

Note: This part of the bare metal code design idea has not been touched before, here is a careful study.
First of all, let's talk about the usage of function pointers: function pointer is a pointer variable pointing to a function, and its essence is a pointer variable.

int (*f)  (int x); /* 声明一个函数指针 */
f=func; /* 将func函数的首地址赋给指针f */

Second, define a function pointer type:

typedef void(*variable)();/*声明一个void(*)() 类型的函数指针variable。*/

See typedef void(*Func)(void) usage

//本函数是注册的定时器中断服务程序
void timer_irq(void)
{
    
    
	int i;
	//这里比较新鲜:作者计划按照调用几个函数进行执行,使用了函数数组的形式
	//TIMER_NUM:最大能够调用函数数量,这里是一个宏
	for (i = 0; i < TIMER_NUM; i++)
	{
    
    
		//timer_array是一个结构体数组,fp是一个函数指针
		//这里依次定义结构体数组中的每一个函数指针对应的函数
		if (timer_array[i].fp)//只要指针非空,则对应的函数被调用;否则,继续调用下一个
		{
    
    
			timer_array[i].fp();
		}
	}	
}

//定义一个函数指针类型
typedef void(*timer_func)(void);
//定义一个结构体类型
typedef struct timer_desc {
    
    
	char *name;
	timer_func fp;
}timer_desc;
//定义一个结构体数组
timer_desc timer_array[TIMER_NUM];

//在结构体数组中添加某个函数
//name:可以理解为函数代号;fp:等待加入的函数指针
int register_timer(char *name, timer_func fp)
{
    
    
	int i;
	for (i = 0; i < TIMER_NUM; i++)
	{
    
    
		//如果这个位置的函数为空,则添加进来;
		//否则,继续向后遍历。
		if (!timer_array[i].fp)
		{
    
    
			timer_array[i].name = name;
			timer_array[i].fp   = fp;
			return 0;
		}
	}
	return -1;
}

//在结构体数组中去掉某个函数
//name:可以理解为函数代号;
void unregister_timer(char *name)
{
    
    
	int i;
	//遍历结构体数组
	for (i = 0; i < TIMER_NUM; i++)
	{
    
    
		//如果遍历到了一个数组中成员的名字与输入参数一致,
		//把对应的成员参数置为空!
		if (!strcmp(timer_array[i].name, name))
		{
    
    
			timer_array[i].name = NULL;
			timer_array[i].fp   = NULL;
			return 0;
		}
	}
	return -1;
}

Guess you like

Origin blog.csdn.net/xiaoaojianghu09/article/details/104399908