网站首页 > 技术文章 正文
来源:百问网_嵌入式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;这节课讲定时器的优化, 下节课讲怎么使用定时器来改进触摸屏
猜你喜欢
- 2024-11-10 VMware中ESXI常用命令(vmware esxi使用教程)
- 2024-11-10 arm嵌入式考试题,大神精心总结(arm嵌入式知识点)
- 2024-11-10 ARM汇编教程(3): ARM指令集(arm汇编指令的基本格式)
- 2024-11-10 Cortex-A的通用寄存器和程序状态寄存器
- 2024-11-10 基于istio的mirror构建真实流量测试环境
- 2024-11-10 领先业界,中兴通讯首发两款双路4K超高清视讯终端
- 2024-11-10 arm 汇编指令 CPS(arm汇编器)
- 2024-11-10 Linux-2.6.37版:Linux内核启动全过程详解
- 2024-11-10 协处理器指令_开启ICache代码示例
- 2024-11-10 90后程序员小伙分享—Linux内核kernel启动分析(下篇)精品推荐
- 最近发表
- 
- 聊一下 gRPC 的 C++ 异步编程_grpc 异步流模式
- [原创首发]安全日志管理中心实战(3)——开源NIDS之suricata部署
- 超详细手把手搭建在ubuntu系统的FFmpeg环境
- Nginx运维之路(Docker多段构建新版本并增加第三方模
- 92.1K小星星,一款开源免费的远程桌面,让你告别付费远程控制!
- Go 人脸识别教程_piwigo人脸识别
- 安卓手机安装Termux——搭建移动服务器
- ubuntu 安装开发环境(c/c++ 15)_ubuntu安装c++编译器
- Rust开发环境搭建指南:从安装到镜像配置的零坑实践
- Windows系统安装VirtualBox构造本地Linux开发环境
 
- 标签列表
- 
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- js判断是否是json字符串 (75)
- c语言min函数头文件 (77)
- asynccallback (87)
- localstorage.removeitem (77)
- vector线程安全吗 (73)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 无效的列索引 (74)
 
