优秀的编程知识分享平台

网站首页 > 技术文章 正文

ADC触摸屏编程_定时器程序优化(触摸屏如何修改plc里时间定时值)

nanyue 2024-11-10 10:18:03 技术文章 1 ℃


来源:百问网_嵌入式Linux wiki_jz2440 新1期视频维基教程 (视频文字版)

作者:韦东山

本文字数:4962,阅读时长:5分钟

第018课 ADC和触摸屏 第007节_触摸屏编程_定时器程序优化

  • 有一个缺点
  • 我们按下触摸屏会输出一个数据,再按下触摸屏又输出一个数据
  • 我长按并没有输出数据,我滑动也没有输出数据
  • 我们需要使用定时器改进这个问题

这个处理流程是怎么样的?

  • 按下期间启动定时器
  • 定时器每过10ms / 20ms就中断一次
  • 在中断函数里测量触电的XY坐标
  • 这样就可以得到连续的数据

打开定时器Timer.c

#include "s3c2440_soc.h"

//定义一个宏 TIMER_NUM = 32
#define TIMER_NUM  32
#define NULL  ((void *)0)

typedef void(*timer_func)(void);

//定义一个结构体 ,既存放有函数指针又存放有数据
typedef struct timer_desc {
	char *name;
	timer_func fp;
}timer_desc, *p_timer_desc;

//我们需要往这个结构体数组里面添加函数,注册Timer函数
timer_desc timer_array[TIMER_NUM];


//注册Timer函数
int register_timer(char *name, timer_func fp)
{
	int i;
//搜索这个数组,如果fp等于0的话,就表示没有占用这个数组项,我就把它填充进去

	for (i = 0; i < TIMER_NUM; i++)
	{
		if (!timer_array[i].fp)
		{	
			 [i].name = name;
			timer_array[i].fp   = fp;
			return 0;
//注册成功
		}
	}
//否则,表示已经满了,注册失败
	return -1;
}

我们不需要使用Timer定时器的时候unregister_timer函数, 考虑到我们需要从数组里面把这个Timer去掉,我们怎么找到这个Timer?
传入一个函数指针,以后卸载使用名字找到对应的项.

void unregister_timer(char *name)
{
//对于unregister_timer就反过来操作,遍历每一项
	int i;
	for (i = 0; i < TIMER_NUM; i++)
	{
//如果这个数组项里面的名字等于我传进来我名字
		if (!strcmp(timer_array[i].name, name))
		{
//也就表示我找到了这两项,设置成NULL
			timer_array[i].name = NULL;
			timer_array[i].fp   = NULL;
			return 0;
		}
	}
//否则return -1;找不到选择的项
	return -1;
}

应该让其从某个数组里面把需要定时器处理的函数依次执行,这样做,我们以后添加定时器处理函数时就不需要修改Timer.c

void timer_irq(void)
{
	int i;
	for (i = 0; i < TIMER_NUM; i++)
	{
//判断指针是否为空,如果不是空的话就继续执行timer_array[i].fp();这个函数
		if (timer_array[i].fp)
		{
			timer_array[i].fp();
		}
	}	
}

如果想继续点灯的话,需要单独注册led_timer_irq 在led.c文件里注册led_timer_irq 把这个函数放在led_timer_irq函数下面,防止编译错误,每10ms该函数被调用一次.

int led_init(void)
{
	/* 设置GPFCON让GPF4/5/6配置为输出引脚 */
	GPFCON &= ~((3<<8) | (3<<10) | (3<<12));
	GPFCON |=  ((1<<8) | (1<<10) | (1<<12));
//led是名字,led_timer_irq是函数指针
	register_timer("led", led_timer_irq);
}

/* 每10ms该函数被调用一次 
 * 每500ms操作一下LED实现计数
 */
void led_timer_irq(void)
{
	/* 点灯计数 */
	static int timer_num = 0;
	static int cnt = 0;
	int tmp;

	timer_num++;
	if (timer_num < 50)
		return;
	timer_num = 0;
//操作led
	cnt++;

	tmp = ~cnt;
	tmp &= 7;
	GPFDAT &= ~(7<<4);
	GPFDAT |= (tmp<<4);
}

修改main.c

int main(void)
{
	led_init();//初始化led
	//interrupt_init();  /* 初始化中断控制器 */
	key_eint_init();   /* 初始化按键, 设为中断源 */
	timer_init();//打开定时器
	
	puts("\n\rg_A = ");
	printHex(g_A);
	puts("\n\r");

	//nor_flash_test();
	lcd_test();

	//adc_test();

	touchscreen_test();

	while (1);
	
	return 0;
}

修改timer.c文件

void timer_init(void)
{
	/* 设置TIMER0的时钟 修改时钟频录让其10ms中断一次 */
	/* Timer clk = PCLK / {prescaler value+1} / {divider value} 
	             = 50000000/(49+1)/16
	             = 62500
	 */
	TCFG0 = 49;  /* Prescaler 0 = 49, 用于timer0,1 */
	TCFG1 &= ~0xf;
	TCFG1 |= 3;  /* MUX0 : 1/16 */

	/* 设置TIMER0的初值 */
	TCNTB0 = 625;  /* 10Ms中断一次 */

	/* 加载初值, 启动timer0 */
	TCON |= (1<<1);   /* Update from TCNTB0 & TCMPB0 */

	/* 设置为自动加载并启动 */
	TCON &= ~(1<<1);
	TCON |= (1<<0) | (1<<3);  /* bit0: start, bit3: auto reload */

	/* 设置中断 */
	register_irq(10, timer_irq);
}

烧写到nandflash发现无输出,可能是前重定位前的代码超出了4k,所以我们使用Norflash启动,发现可以正常运行

我们修改Makefile把负责重定位代码往前移,其他无关代码往后放,接着看star.S

.text
.global _start

_start:
	b reset          /* vector 0 : reset */
	ldr pc, und_addr /* vector 4 : und */
	ldr pc, swi_addr /* vector 8 : swi */
	b halt			 /* vector 0x0c : prefetch aboot */
	b halt			 /* vector 0x10 : data abort */
	b halt			 /* vector 0x14 : reserved */
	ldr pc, irq_addr /* vector 0x18 : irq */
	b halt			 /* vector 0x1c : fiq */

//我们需要把这些异常往后放
und_addr:
	.word do_und

swi_addr:
	.word do_swi

irq_addr:
	.word do_irq

reset:
	/* 关闭看门狗 */
	ldr r0, =0x53000000
	ldr r1, =0
	str r1, [r0]

	/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
	/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
	ldr r0, =0x4C000000
	ldr r1, =0xFFFFFFFF
	str r1, [r0]

	/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */
	ldr r0, =0x4C000014
	ldr r1, =0x5
	str r1, [r0]

	/* 设置CPU工作于异步模式 */
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA
	mcr p15,0,r0,c1,c0,0

	/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 
	 *  m = MDIV+8 = 92+8=100
	 *  p = PDIV+2 = 1+2 = 3
	 *  s = SDIV = 1
	 *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
	 */
	ldr r0, =0x4C000004
	ldr r1, =(92<<12)|(1<<4)|(1<<0)
	str r1, [r0]

	/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
	 * 然后CPU工作于新的频率FCLK
	 */

	/* 设置内存: sp 栈 */
	/* 分辨是nor/nand启动
	 * 写0到0地址, 再读出来
	 * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
	 * 否则就是nor启动
	 */
	mov r1, #0
	ldr r0, [r1] /* 读出原来的值备份 */
	str r1, [r1] /* 0->[0] */ 
	ldr r2, [r1] /* r2=[0] */
	cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */
	ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
	moveq sp, #4096  /* nand启动 */
	 streq r0, [r1]   /* 恢复原来的值 */

	bl sdram_init
	//bl sdram_init2	 /* 用到有初始值的数组, 不是位置无关码 */

	/* 重定位text, rodata, data段整个程序 */
	bl copy2sdram

	/* 清除BSS段 */
	bl clean_bss

	/* 复位之后, cpu处于svc模式
	 * 现在, 切换到usr模式
	 */
	mrs r0, cpsr         /* 读出cpsr */
	bic r0, r0, #0xf     /* 修改M4-M0为0b10000, 进入usr模式 */
	bic r0, r0, #(1<<7)  /* 清除I位, 使能中断 */
	msr cpsr, r0

	/* 设置 sp_usr */
	ldr sp, =0x33f00000

	ldr pc, =sdram
sdram:
	bl uart0_init

	bl print1
	/* 故意加入一条未定义指令 */
init.c 需要放在前面
nand_init
sdram_init初始化也放前面
sdram:

bl uart0_init

这就跳到sdram了,重定位后就随便操作

修改Makefile 我们把 start.o init.o nand_flash.o放在最前面

objs = start.o init.o nand_flash.o led.o uart.o main.o exception.o interrupt.o timer.o nor_flash.o my_printf.o string_utils.o lib1funcs.o

objs += lcd/font.o
objs += lcd/framebuffer.o
objs += lcd/geometry.o
objs += lcd/lcd.o
objs += lcd/lcd_4.3.o
objs += lcd/lcd_controller.o
objs += lcd/lcd_test.o
objs += lcd/s3c2440_lcd_controller.o
objs += lcd/font_8x16.o

objs += adc_touchscreen/adc.o
objs += adc_touchscreen/adc_test.o

objs += adc_touchscreen/touchscreen.o
objs += adc_touchscreen/touchscreen_test.o


all: $(objs)
	#arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf
	arm-linux-ld -T sdram.lds $^ libgcc.a -o sdram.elf
	arm-linux-objcopy -O binary -S sdram.elf sdram.bin
	arm-linux-objdump -D sdram.elf > sdram.dis
clean:
	rm -f *.bin $(objs) *.elf *.dis
	
%.o : %.c
	arm-linux-gcc -march=armv4 -c -o $@ lt;

%.o : %.S
	arm-linux-gcc -march=armv4 -c -o $@ lt;

这节课讲定时器的优化, 下节课讲怎么使用定时器来改进触摸屏


「新品首发」STM32MP157开发板火爆预售!首批仅300套

Tags:

最近发表
标签列表