TFT彩屏工作原理

TFT是如何工作的 TFT就是“Thin Film Transistor”的简称,一般代指薄膜液晶显示器,而实际上指的是薄膜晶体管(矩阵)—— 可以“主动的”对屏幕上的各个独立的象素进行控制,这也就是所谓的主动矩阵TFT(active matrix TFT)的来历。那么图象究竟是怎么产生的呢?基本原理很简单:显示屏由许多可以发出任意颜色的光线的象素组成,只要控制各个象素显示相应的颜色就能达到目的了。在TFT LCD中一般采用背光技术,为了能精确地控制每一个象素的颜色和亮度就需要在每一个象素之后安装一个类似百叶窗的开关,当“百叶窗”打开时光线可以透过来,而“百叶窗”关上后光线就无法透过来。当然,在技术上实际上实现起来就不像刚才说的那么简单。LCD(Liquid Crystal Display)就是利用了液晶的特性(当加热时为液态,冷却时就结晶为固态),一般液晶有三种形态:

类似粘土的层列(Smectic)液晶

类似细火柴棒的丝状(Nematic)液晶

类似胆固醇状的(Cholestic)液晶

液晶显示器使用的是丝状,当外界环境变化它的分子结构也会变化,从而具有不同的物理特性——就能够达到让光线通过或者阻挡光线的目的——也就是刚才比方的百叶窗。

大家知道三原色,所以构成显示屏上的每个象素需上面介绍的三个类似的基本组件来构成,分别控制红、绿、蓝三种颜色。

目前使用的最普遍的是扭曲向列TFT液晶显示器(Twisted Nematic TFT LCD),下图就是解释的此类TFT显示器的工作原理。现存的技术差别很大,我们将会在本文的第二部分中详细介绍。

在上、下两层上都有沟槽,其中上层的沟槽是纵向排列,而下层是横向排列的。当不加电压液晶处于自然状态,从发光图2a扭曲向列TFT显示器工作原理图示意图层发散过来的光线通过夹层之后,会发生90度的扭曲,从而能在下层顺利透过。

当两层之间加上电压之后,就会生成一个电场,这时液晶都会垂直排列,所以光线不会发生扭转——结果就是光线无法通过下层。

(2)TFT象素架构:彩色滤光镜依据颜色分为红、绿、蓝三种,依次排列在玻璃基板上组成一组(dot pitch)对应一个象素每一个单色滤光镜称之为子象素(sub-pixel)。也就是说,如果一个TFT显示器最大支持1280×1024分辨率的话,那么至少需要1280×3×1024个子象素和晶体管。对于一个15英寸的TFT显示器(1024×768)那么一个象素大约是0.0188英寸(相当于0.30mm),对于18.1英寸的TFT显示器而言(1280×1024),就是0.011英寸(相当于0.28mm)。

大家知道,象素对于显示器是有决定意义的,每个象素越小显示器可能达到的最大分辨率就会越大。不过由于晶体管物理特性的限制,现阶段TFT每个象素的大小基本就是0.0117英寸(0.297mm),所以对于15英寸的显示器来说,分辨率最大只有1280×1024。

M1卡做电子钱包

M1卡做电子钱包使用时,要将某个块按规定格式初始化为数值块

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

数值

数值

数值

Adr

Adr

Adr

Adr

0字节是数值最低字节。

初始数值块是用写命令把数据写到块,例如第8块初始化为数值块,数值为0,用写块命令写入

0x00 0x00 0x00 0x00 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00 0x08 0xf7 0x08 0xf7

然后可以用DECREMENT INCREMENT TRANSFER RESTORE命令对数值块进行操作。

INCREMENT 对存储在数值块中的数值做加法操作,并将结果存到临时数据寄存器

DECREMENT 对存储在数值块中的数值做减法操作,并将结果存到临时数据寄存器

TRANSFER 将临时数据寄存器的内容写入数值块

RESTORE 将数值块内容存入临时数据寄存器

电子钱包增值函数流程

询卡-防冲突-选卡-密码验证-增值-传送-挂起

电子钱包减值函数流程

询卡-防冲突-选卡-密码验证-减值-传送-挂起

RESTORE命令是在一个扇区内数值块进行拷贝时用的,一般钱包数据需要备份在同一扇区的不同块中,则备份和恢复时都要用到RESTORE命令。

数值时一个带符号4字节值,这个值的最低一个字节保存在最低的地址中,所以增加1时,4字节增加的值数组应该是0x01 0x00 0x00 0x00,不是0x00 0x00 0x00 0x01

M1卡使用过程中常见问题及处理建议(转)

M1卡也称感应式IC卡的,只智能IC卡的一种,一般常用的有S50M1卡和S70M1卡,以及国产的兼容S50和S70的复旦F08的M1卡等。

    M1卡在开发及使用过程中总是出现各种各样问题,总结多年在制卡行业的经验,主要引起M1卡操作错误的问题总结起来有以下几种。

一、盲目操作

     造成某些区块误操作被锁死不能再使用。应当仔细参考表3表5的控制权限后,予先得出操作后的结果是否适合使用要求,并且列出操作顺序表单再操作。最好授权程序员对块3的设置作专人操作。

二、丢失密码

再读写时造成密码认证出错而不能访问卡。特别要求在对M1卡进行块3编程操作时,必须及时记录相关卡号的控制值,KeyA,KeyB等,而且应当有专人管理密码档案。

三、 错误设置

       对M1卡的块3控制块了解不透彻,错误的理解造成设置造成错误的设置。依照表2可知,目前M1卡的控制块仅只有8种数据块访问控制权限和8种控制块设置权限,超出这16种权限的其他代码组合,将直接引起错误设置而使卡片报废!

继续阅读

STM32驱动不带字库12864LCD

STM32驱动5V的12864LCD,控制脚和数据较最好接到STM32能容忍5v的IO口,外加上拉电阻时,控制脚和数据脚设置成开漏输出。不加上拉电阻时,控制脚设置为推拉输出,数据脚输出时,设置成推拉输出,输入时设置成上拉输入。加不加上拉电阻都能点亮LCD,关键是脚位配置。

GPIOE的PE0-PE7做数据线,控制线定义如下:

//————-PORTE———————

#define R_S GPIO_Pin_8

#define R_W GPIO_Pin_9

#define EN GPIO_Pin_10

#define _CS1 GPIO_Pin_11

#define _CS2 GPIO_Pin_12

#define _RST GPIO_Pin_13

首先IO口初始化

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOE, &GPIO_InitStructure);

GPIO_ResetBits(GPIOE, EN );

GPIO_SetBits(GPIOE,_CS1 | _CS2 );

注意_CS1,_CS2初始化是一定要拉高,否则检测忙信号时,忙信号会一直是高。我就是因为这个问题卡了好几天。

以下是LCD驱动程序:

//指令宏定义

#define Display_On 0x3f //显示开指令

#define Display_Off 0x3e //显示关指令

#define Y_Col_Addr 0x40 //定位到第0列指令(列起始地址)(0-63)

#define X_Page_Addr 0xb8 //定位到第0页指令(页起始地址)(0-7)

#define Start_Line 0xc0 //定位从DDROM中的第0行开始往屏幕上显示

继续阅读

Cortex-m3的8字节对齐(转帖)

一、什么是栈对齐?

栈的字节对齐,实际是指栈顶指针须是某字节的整数倍。因此下边对系统栈与MSP,任务栈与PSP,栈对齐与SP对齐 这三对概念不做区分。另外下文提到编译器的时候,实际上是对编译器汇编器连接器的统称。

之前对栈的8字节对齐理解的不透,就在网上查了好多有关栈字节对齐、还有一些ARM对齐伪指令的资料信息,又做了一些实验,把这些零碎的信息拼接在一起,总觉得理解透这个问题的话得长篇大论了。结果昨天看了AAPCS手册、然后查到了没有使用PRESERVE8伪指令出现错误的实例,突然觉得长篇大论不存在了,半篇小论这问题就能理顺了。

二、AAPCS栈使用规约

在ARM上编程,但凡涉及到调用,就需要遵循一套规约AAPCS:《Procedure Call Standard for the ARM Architecture》。这套规约里面对栈使用的约定如下:

5.2.1.1
Universal stack constraints
At all times the following basic constraints must hold:
Stack-limit < SP <= stack-base. The stack pointer must lie within the extent of the stack.
SP mod 4 = 0. The stack must at all times be aligned to a word boundary.
A process may only access (for reading or writing) the closed interval of the entire stack delimited by [SP, stack-base – 1] (where SP is the value of register r13).
Note
This implies that instructions of the following form can fail to satisfy the stack discipline constraints, even when reg points within the extent of the stack.
ldmxx reg, {…, sp, …} // reg != sp
If execution of the instruction is interrupted after sp has been loaded, the stack extent will not be restored, so restarting the instruction might violate the third constraint.
5.2.1.2
Stack constraints at a public interface
The stack must also conform to the following constraint at a public interface:
SP mod 8 = 0. The stack must be double-word aligned.

可以看到,规约规定,栈任何时候都得4字节对齐,在调用入口得8字节对齐。

在这个约定里,栈的4字节对齐确实得任何时候都遵守,而且你想不遵守都难,因为SP的最后两位是硬件上保持0的。而对于8字节对齐,这就需要码农和编译器配合着来。需要说明的一点是,8字节对齐即使不遵守,一些情况下也没问题,只要主调和被调用例程两边把堆栈使用,传参,返回等处理好就行,也就是说两边有自己的一套约定就行。但是有时候,主调这边在调用严格遵守AAPCS的函数时,没有将栈保持在8字节对齐上,那就会出问题。

三、如何编程?

继续阅读

STM32库起始文件堆栈分配(转帖)

定义大小在startup_stm32f10x_hd.s

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp

; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base

2.堆和栈位置

通过MAP文件可知

HEAP                                     0x200106f8   Section      512  startup_stm32f2xx.o(HEAP)
STACK                                    0x200108f8   Section     1024  startup_stm32f2xx.o(STACK)

__heap_base                              0x200106f8   Data           0  startup_stm32f2xx.o(HEAP)
__heap_limit                             0x200108f8   Data           0  startup_stm32f2xx.o(HEAP)
__initial_sp                             0x20010cf8   Data           0  startup_stm32f2xx.o(STACK)

显然 Cortex-m3资料可知:__initial_sp是堆栈指针,它就是FLASH的0x8000000地址前面4个字节(它根据堆栈大小,由编译器自动生成)

显然堆和栈是相邻的。

3.堆和栈空间分配

栈:向低地址扩展

堆:向高地址扩展

显然如果依次定义变量

先定义的栈变量的内存地址比后定义的栈变量的内存地址要大

先定义的堆变量的内存地址比后定义的堆变量的内存地址要小 

4.堆和栈变量

栈:临时变量,退出该作用域就会自动释放

堆:malloc变量,通过free函数释放

另外:堆栈溢出,编译不会提示,需要注意

Lwip在UCOS-II上的移植(三)

移植网络驱动程序。在netif文件夹下有ethernetif.c,就是网络芯片的驱动程序,需要对照实际使用的网络芯片修改。下面是DM9000A的在lwip下的驱动的程序。

/* Define those to better describe your network interface. */

#define IFNAME0 ‘d’

#define IFNAME1 ‘m’

#define NIC_BASE 0x82000000

#define NIC_REG_ADDR (*(volatile u8_t *) 0x82000000)

/* if cmd link to system bus A2 */

#define NIC_REG_DATA_byte (*(volatile u8_t *) 0x82000004)

#define NIC_REG_DATA_word (*(volatile u16_t *) 0x82000004)

/* for dm9000a function setting */

#define Fix_Note_Address

#define DM9000A_FLOW_CONTROL

#define Rx_Int_enable

static void low_level_init(struct netif * netif);

static err_t low_level_output(struct netif * netif,struct pbuf *p);

static void ethernetif_input(struct netif *netif);

struct pbuf * low_level_input(struct netif *netif);

u16_t DM9000A_Phy_Read (u8_t offset);

void udelay(u32_t time)

{

//wait_1us(time);

while (–time > 0);

}

u8_t ior(u8_t reg_addr)

{

NIC_REG_ADDR = reg_addr;

return (NIC_REG_DATA_byte);

}

继续阅读

Lwip在UCOS-II上的移植(二)

把下载的Lwip文件夹放到项目文件中,项目文件夹入下图:

clip_image002

Lwip包含的功能:

1、 ARP协议,以太网地址解析协议

2、 IP协议,包括IPv4和IPv6,支持IP分片与重装,支持多网络接口下数据包转发

3、 IGMP协议,用于网络组管理,可以实现多播数据的接收

4、 UDP协议,用户数据报协议

5、 TCP协议,支持TCP拥塞控制,RTT估计,快速恢复与重传等

6、 提供三种用户编程接口方式:raw/callback API,sequential API,BSD-style socket API

7、 DNS,域名解析

8、 SNMP,简单网络管理协议

9、 DHCP,动态主机配置协议

10、 AUTOIP,IP地址自动配置

11、 PPP,点对点协议,支持PPPoE

下载的LWIP源代码包括3个文件夹,doc,src和test。doc 文件夹包含了几个与协议栈使用相关的文档。Test文件夹下是lwip提供的一些协议栈内核测试程序,移植不会用到。Src文件夹里就是lwip的所有源代码,需要放到项目文件中,上图中的lwip文件夹下就是src文件夹里的内容。

Api文件包含了lwip的sequential API和socket API两类接口函数及实现相关的源代码,要使用这两种类型的API,需要底层操作系统的支持。Core文件夹是lwip的内核源代码,内核源代码可以单独运行,且不需要操作系统的支持。Include主要包含整个协议栈使用的头文件。Netif主要包含了与底层网络接口相关的文件。

Lwip在UCOS-II上的移植(一)

LwIP是Light Weight (轻型)IP协议,有无操作系统的支持都可以运行。LwIP实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用,它只需十几KB的RAM和40K左右的ROM就可以运行,这使LwIP协议栈适合在低端的嵌入式系统中使用。

Lwip的官方下载地址:http://savannah.nongnu.org/projects/lwip/

ARM和网络芯片(例如DM9000A)通讯,DM9000A接收到网络传送的数据包后,产生中断,ARM 检测到中断后从DM9000A接收缓冲区读取数据包,利用Lwip的内部数据包管理函数,把接收的数据包放在一个pbuf结构中。Lwip判断当前的数据包是ARP包还是IP包,调用相应的函数进行处理。

Lwip实现有几种方式:1、raw\callback API 2、sequential API 3、socket API

采用第1种方式时,Lwip做为UCOS中的一个单独的任务。用户程序和协议栈之间的通讯通过回调函数实现。所有网络相关的处理都在同一个任务里完成,避免了任务的切换。在嵌入式操作系统中使用Lwip时,最好将Lwip任务设为系统的最高优先级,以提高协议栈的实时性。

另外两种方式没有使用过,这两种方式需要使用操作系统的信号量和邮箱机制。对一些小的嵌入式系统和工作频率不高的ARM芯片来说,频繁的切换任务时没有必要的。使用第一种回调方式实现,我觉得是比较合适的。

开发之旅

某一天,你接到一个任务,要去某一个地方,沿途要经过一些站点。接到任务时,你满怀信心,觉得一定会一路顺畅。你出发了,开始的路程很轻松,道路平坦,路边鸟语花香,你按照计划经过了几个必须路过的站点。终点就在远处的山顶,好像就快要到了。

又走了一段路程,路面开始崎岖不平,而且开始有岔路口。你开始犹豫不前,你选择岔路口的一条路,往前走了一段,发现有某个必须经过的站点没有看到。没办法,只好往回走,选择另一条路。这样不断的选择,返回,前进,再选择,返回,前进。你已经被折腾的有些沮丧了。但是必须得坚持前进。

终于计划中要经过的站点都走过了,开始向山顶的终点冲刺。路已经变的非常陡峭,终点好像变的遥不可及。你的心底掠过一丝放弃的念头。作为一个程序员,放弃就意味着职业生涯的终结。你咬着牙继续往上爬。越过一个个障碍,最后你看到一条小路,好像直达山顶。太好了,总算快到了,你的心情无比轻松,停下来休息了一会,欣赏周围的美景,觉得自信又回来了。

休息够了,你浑身充满了力量,沿着那条小路往山顶进发。但是走着走着,你发现这条小路竟然是条绝路,前面有巨石档道,无论如何都不能翻过到达终点。你在这条小路的终点徘徊不前,试了无数的办法,还是没发越过巨石,你觉得你快要崩溃了,忍不住想大喊。你休息一会,继续爬,累了,再休息一会,再继续爬。终于你的自信心完全丧失了,严重怀疑自己是不是入错了行当,根本不是做程序员的料。想就此放弃,但是回看已经走了那么远的路程,心有不甘。在那里停留几天,你开始变的冷静。仔细的评估周围的环境和自己的精力,判断自己能爬过去。你做好了打持久站的准备,开始一点一滴的凿掉巨石,一步一个脚印往上爬,开始你以为要很久才能凿出一条道,没想到几天之后就到了巨石的上方。

终于到了山顶,你心里有一丝欣喜,但更多的是踏实,你知道这个任务完成的不错。站在山顶的时候,没有狂妄,只有谦卑。远处还有更高的山,但是从这次的开发之旅,你已经知道了开发的心路历程,信心已经在心中生根,其它的山峰你终将能够到达。

第 5 页,共 8 页« 最新...34567...最旧 »