网站首页 > 技术文章 正文
来源:百问网_嵌入式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启动分析(下篇)精品推荐
- 最近发表
-
- 使用Knative部署基于Spring Native的微服务
- 阿里p7大佬首次分享Spring Cloud学习笔记,带你从0搭建微服务
- ElasticSearch进阶篇之搞定在SpringBoot项目中的实战应用
- SpringCloud微服务架构实战:类目管理微服务开发
- SpringBoot+SpringCloud题目整理
- 《github精选系列》——SpringBoot 全家桶
- Springboot2.0学习2 超详细创建restful服务步骤
- SpringCloud系列:多模块聚合工程基本环境搭建「1」
- Spring Cloud Consul快速入门Demo
- Spring Cloud Contract快速入门Demo
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)