月度归档:2014年07月

UCOS-II中数据类型移植

在OS_CPU.H文件中,定义了UCOS系统使用的数据类型,在ARM中移植时

typedef unsigned char BOOLEAN;

typedef unsigned char INT8U;

typedef signed char INT8S;

typedef unsigned short INT16U;

typedef signed short INT16S;

typedef unsigned int INT32U;

typedef signed int INT32S;

typedef float FP32;

typedef double FP64;

在ARM中unsigned int 是32位,而在51中,unsigned int 是16位。在51中移植如下:

typedef unsigned char BOOLEAN;

typedef unsigned char INT8U;

typedef signed char INT8S;

typedef unsigned int INT16U;

typedef signed int INT16S;

typedef unsigned long INT32U;

typedef signed long INT32S;

typedef float FP32;

typedef double FP64;

其中BOOLEAN、INT8U、INT8S、INT16U、INT16S、INT32U、INT32S、FP32、FP64是UCOS源文件使用的数据类型。unsigned int等是ADS编译器或51编译器使用的数据类型。

UCOS-II书中说,UCOS-II不使用C语言中的short,int,long等数据类型,因为它们与处理器类型有关,隐含不可移植性,代之以移植性强的整型数据。既直观又可移植。意思就是UCOS-II中使用BOOLEAN、INT8U、INT8S、INT16U、INT16S、INT32U、INT32S、FP32、FP64数据类型。移植到不同的处理器时,这些数据类型要根据使用的C编译器重新定义。

S3C2440开发板中SDRAM \NOR FLASH\ NAND FLASH地址分配

前三篇文章里,我分析了S3C2440与SDRAM,NOR FLASH,NAND FLASH的连线。在S3C2440开发板这个系统中,这三种存储芯片的地址是如何分配的呢?

首先看下图:

clip_image001

这是S3C2440的存储器地址分配图,SDARM只能接在BANK6或BANK7.从分析SDRAM接线的文章里的SDRAM接线图可以看到,SDRAM接的是ngcs6,也就是接在BANK6,因为选择的SDRAM是2片32Mbyte,总容量是64Mbyte,所以SDRAM的地址范围是

0×3000 0000 — 0×33ff ffff。

S3C2440的OM0,OM1脚决定系统启动模式:

clip_image002

继续阅读

S3C2440与NAND FLASH(K9F1208)的接线分析

NAND FLASH的接线方式和NOR FLASH,SDRAM都不一样。以TQ2440开发板用的K9F1208为例,分析NAND FLASH的接线方式。

K9F1208结构如下图:

clip_image001

K9F1208位宽是8位。

一页: 512byte + 16byte 最后16byte是用于存储校验码和其他信息用的,不能存放实际的数据。

一个块有32 page:(16k+512)byte

K9F1208有4096个块:(64M+2M)byte,总共有64Mbyte可操作的芯片容量

NAND FLASH以页为单位读写数据,以块为单位擦除数据。

S3C24440和K9F1208的接线图如下:

clip_image002
下图是S3C2440的NAND FLASH引脚配置:

clip_image003

当选定一个NAND FLASH的型号后,要根据选定的NAND FLASH来确定S3C2440的NCON,GPG13,GPG14,GPG15的状态。

继续阅读

S3C2440与NOR FLASH(AM29LV160DB)的接线分析

NOR FLASH的特点是芯片内执行(XIP, eXecute In Place),这样应用程序可以直接在flash 闪存内运行,不必再把代码读到系统RAM中。NOR的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响了它的性能。

NOR FLASH的地址线和数据线是分开的。

AM29LV160DB是一个2Mbyte的NOR FLASH,分区结构是:

1个16Kbyte扇区,2个8Kbyte扇区,1个32Kbyte扇区,31个64Kbyte扇区(字节模式)

1个8Kbyte扇区,2个4Kbyte扇区,1个16Kbyte扇区,31个32Kbyte扇区(半字模式)

共35个扇区。

继续阅读

S3C2440与SDRAM的地址连线分析

S3C2440有27根地址线ADDR[26:0],8根片选信号ngcs0-ngcs7,对应bank0-bank7,当访问bankx的地址空间,ngcsx引脚为低电平,选中外设。

2^27=2^7 * 2^10 * 2^10 = 128Mbyte

8*128Mbyte = 1Gbyte

所以S3C2440总的寻址空间是1Gbyte。

市面上很少有32位宽度的单片SDRAM,一般选择2片16位SDRAM扩展得到32位SDRAM.

选择的SDARM是HY57V561620F,4Mbit * 4bank *16,共32Mbyte。

首先了解下SDRAM的寻址原理。

SDRAM内部是一个存储阵列。可以把它想象成一个表格。和表格的检索原理一样,先指定行,再指定列,就可以准确找到所需要的存储单元。这个表格称为逻辑BANK。目前的SDRAM基本都是4个BANK。寻址的流程就是先指定BANK地址,再指定行地址,最后指定列地址。这就是SDRAM的寻址原理。存储阵列示意图如下:

clip_image001

查看HY57V561620F的资料,这个SDRAM有

13根行地址线 RA0-RA12

9根列地址线 CA0-CA8

2根BANK选择线 BA0-BA1

SDRAM的地址引脚是复用的,在读写SDRAM存储单元时,操作过程是将读写的地址分两次输入到芯片中,每一次都由同一组地址线输入。两次送到芯片上去的地址分别称为行地址和列地址。它们被锁存到芯片内部的行地址锁存器和列地址锁存器。/RAS是行地址锁存信号,该信号将行地址锁存在芯片内部的行地址锁存器中;/CAS是列地址锁存信号,该信号将列地址锁存在芯片内部的列地址锁存器中。

继续阅读

C函数预处理防重复定义变量用法

嵌入式开发中,文件比较多,有很多全局变量需要在不同文件中引用。一般在头文件和C文件中采用预处理命令来避免变量的重复定义。

先看一例:

在Main.c文件的开始

#define MAIN_GLOBALS

#include “main.h”

在main.h文件开始

#ifdef MAIN_GLOBALS //如果存在宏定义

#define MAIN_EXT //定义MAIN_EXT为空

#else //否则

#define MAIN_EXT extern //定义MAIN_EXT为extern

#endif

MAIN_EXT uchar Car_Out,OldOut;

MAIN_EXT uchar Car_Out1,OldOut1;

MAIN_EXT uchar Car_Out2,OldOut2;

MAIN_EXT uchar Car_In,OldIn;

MAIN_EXT uchar Car_In1,OldIn1;

通过上面的2个文件可以看出,在main.c中,因为定义了宏MAIN_GLOBALS,包含头文件main.h 后,在main.c中定义了car_out,oldout等变量。

如果在其他的c文件中包含main.h,因为c文件中没有定义宏MAIN_GLOBALS,所以MAIN_EXT就是extern,也就是在其它c文件中声明car_out,oldout等变量。这样就避免了重复定义。

二代身份证读卡器开发小结

最近用RC531开发了一款可以同时读IC卡和身份证的读卡器。网上读IC卡的程序很多,没什么好介绍的。这里总结下读身份证要注意的几个问题。

我做的身份证读卡器只是读身份证的ID号,身份证的内部内容是无法读出的。

身份证读卡器的程序流程如下:

先发送0x05,0x00,0x00询卡命令后,身份证返回12字节卡类型代码,不同身份证返回的数据不一样。比如我对两个身份证发送询卡命令后分别返回

0x50 0x00 0x00 0x00 0x00 0xd1 0x03 0x86 0x0c 0x00 0x80 0x80

0x50 0x00 0x00 0x00 0x00 0xd1 0x03 0x86 0x07 0x00 0x80 0x90

询卡成功后,发送SELECT命令:0x1d 0x00 0x00 0x00 0x00 0x00 0x08 0x01 0x08 对二代身份证进行选卡操作。这时身份证返回的第一个字节应该等于SELECT命令的最后一个字节0x08,根据这个条件来判断SELECT命令是否操作成功。

最后发送GUID命令:0x00 0x36 0x00 0x00 0x08,身份证会返回10字节数据,其中前8字节就是身份证的唯一ID,后两字节是0x90 0x00。可以用后两字节来判断得到的是否是身份证ID。

要注意的是二代身份证是TYPEB卡,但是用TYPEB卡的HALT命令对它不起作用。把身份证放在读卡器上会一直读卡。这个问题只能用软件解决,比如在500ms内检测到同一个ID号,只输出一次韦根信号。

我在测试时发现,有时把身份证放在读卡器上,会读不到卡。但是程序是一直循环发送询卡命令,SELECT命令,GUID命令的。我分析原因应该是身份证内部芯片死机了。因为身份证内部电路是靠射频供电的,如果读卡器一直发送射频信号,当身份证内部芯片死机后,由于外部一直有射频信号,所以内部芯片一直有电压,芯片也一直维持死机状态,即使不断重新发送命令也无济于事。解决这个问题的办法就是在每次发送询卡命令,SELECT命令,GUID命令前,先关闭射频信号,延时20ms后再打开射频信号,再延时10ms,然后发送命令。关闭射频信号的目的是让身份证内部电路断电,重新发送射频信号后,让芯片复位。这样修改后每次都能读到ID号。

继续阅读

韦根26韦根34发送程序

WG26协议

Wiegand 26格式:

各数据位的含义:

第 1 位: 为输出数据2—13位的偶校验位

第 2—9 位:  ID卡的HID码的低8位

第10-25位:  ID卡的PID号码

第 26 位: 为输出数据14-25位的奇校验位

数据输出顺序:

HID码和PID码均为高位在前,低位在后

例:一张ID卡内容为:

HID:32769 PID:34953 ( 卡面印:2147584137 001, 34953 )

相应的二进制为:

HID:1000 0000 0000 0001 ( 只输出低8位 )

PID:1000 1000 1000 1001

输出如下:

1 2 9 10 25 26

0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 1

| HID_L | PID |

输出端D0、D1时序:

图示:

clip_image001

(1) D0、D1在没有数据输出时均保持高电平;

(2) 输出数据位时间为420uS(TL),如输出为0,D0拉低420uS(TL)后为高电平,若输出为1,则D1拉低420uS(TL)后为高电平;

输出数据位之间的间隔时间为2mS(TL),如输出00:D0拉低420uS(TL)后为高电2mS(TL),再拉低为低电平420uS(TL),然后释放为高电平;

WG34协议

Wiegand 34格式:

各数据位的含义:

第 1 位: 为输出第2—17位的偶校验位

第 2-17 位:  ID卡的HID码

第18-33位:  ID卡的PID号码

第 34 位: 为输出第18-33位的奇校验位

数据输出顺序:

HID码和PID码均为高位在前,低位在后

例:一张ID卡内容为:

HID:32769 PID:34953 ( 卡面印:2147584137 001, 34953 )

相应的二进制为:

HID:1000 0000 0000 0001

PID:1000 1000 1000 1001

输出如下:

1 2 17 18 33 34

0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0

| HID_L | PID |

输出端D0、D1时序:

图示:

clip_image001[1]

(3) D0、D1在没有数据输出时均保持高电平;

继续阅读

STM32串口发送时序图分析

下面是STM32使用手册上的串口发送时序图:

clip_image002

1、 使能串口发送TE,此时USART_DR为空,此时应查询TXE是否置1,TXE置1,TX脚先发送一个空闲帧,把F1帧写入USART_DR,TXE被清零。因为这时正在发送空闲帧,所以写入USART_DR的数据被放入TDR寄存器,还没有拷贝到移位寄存器。

2、 在空闲帧发送完后,TDR寄存器中的数据被拷贝到移位寄存器,此时应查询TXE是否置1,TXE置1,表示TDR已空,可以放入下一个数据。此时在TX脚上将会发送F1帧的数据,同时软件把F2帧的数据写入USART_DR,TXE被清零。

3、 在F1帧的停止位发送完后,因为TDR寄存器中的F2还没被拷入移位寄存器,所以此时TXE仍为0,TC不置1.此时应查询TXE是否置1,TXE置1,表示TDR已空,可以放入下一个数据。此时在TX脚上将会发送F2帧的数据,同时软件把F3帧的数据写入USART_DR,TXE被清零。

4、 在F2帧的停止位发送完后,因为TDR寄存器中的F3还没被拷入移位寄存器,所以此时TXE仍为0,TC不置1.此时应查询TXE是否置1,TXE置1,表示TDR已空,后面没有数据写入USART_DR,TXE保持高电平,此时在TX脚上将会发送F3帧的数据。

5、 在F3帧的停止位发送完后,因为此时TXE为1,所以TC标志会置1.如果TCIE为1,将会产生中断。

继续阅读

C51扩展外部RAM释放P2口

51单片机经常要使用一些外部器件,有些器件内部有寄存器,一般都把这些寄存器当做外部RAM读写。以IC卡读卡芯片RC500为例,这个芯片有D0-D7共8个数据线,接在51的P0口,D0-D7既做地址线也做数据线。RC500的NWR、NRD、ALE与51单片机的WR、RD、ALE相连。RC500内部寄存器地址范围是00-0XFF。此时如果把RC500的片选CS接在P2.7,那么要读RC500内部地址0X34的值,可以用*0X7F34读得。向0X34写入value可以用*0x7F34=value来实现。

这样编译后查看汇编语言可以看到读写RC500采用的是MOVX A,@DPTR命令,也就是说在读写器件寄存器时,P0口发送寄存器低地址0X00-0XFF,P2口发送高地址0X7F。在单片机I/O口紧张的情况下,这种用法P2口除了扩展其它外部RAM外,就不能做其它用途了。比如不能接按键扫描。因为每次读写RC500寄存器都会改变P2口的电平。按键扫描I/O口电平肯定就不对了。

那么如何释放P2口?51读写外部RAM还有一条指令MOVX A,@R0,这条指令选择外部RAM时,只输出8位地址到P0口,不影响P2口。还以RC500为例。读写寄存器可以如下处理:

#define ReadIO(x) (*(uchar volatile pdata *)(x))

#define WriteIO(x,rc500data) ((*(uchar volatile pdata *)(x)) = rc500data)

这条语句的关键是pdata。采用这种方法编译后汇编语句就是MOVX A,@R0。这样P2口就可以用做其它用途了。不过这种方式下,RC500的片选要单独用一条语句来实现。不像MOVX A,@DPTR执行时,已经执行了片选动作。

第 1 页,共 2 页12