转自:http://blog.csdn.net/striker211/article/details/7432685
其实接触CSDN好久了,一直没有想写自己的博客,遇到问题的时候才去上CSDN参考别人的资料,想到以后不能脚踩西瓜皮,滑倒哪里是哪里,要一个萝卜一个坑,用CSDN博客记录下自己的每一个脚印,一来自己以后可以回过来温故知新,二来很高兴为后来人做一个可参考的基石。毕设了,打算用MDK去开发TQ2440,题目是单片机的液压控制系统,其中,会用到TLC2543芯片的AD转换器,TLC2543是12位精度的SPI接口的AD芯片,起初用网上便宜的8位AD芯片PCF8591,好不容易用TQ2440自带的IIC总线调通了AD的读取,老师说精度太低,换!这不,我就选取了TLC2543芯片,原以为调试SPI和IIC一样简单,谁知道,真正调试的时候,遇到各种问题,首先采用的是SPI查询方式,读取的数据一直不确定,检查电路无误之后,上网查遍了S3C2440读取TLC2543的资料,发现资料太少了,唯一可参考的是一位西安交大毕设论文,描述的是linux下的S3C2440的TLC2543读取的驱动的编写。发现了一些错误,但是论文写的遮遮掩掩,并不完全透明。无奈之下,我放弃了SPI接口的编写,网上更多的GPIO模拟的驱动,我搜索了一下,S3C2440的SPI模拟的程序还真没有人写过,我就在此记录一下了。
- #include "2440addr.h"
- #include "AD.h"
- #define CLK(value) (rGPGDAT = (rGPGDAT & ~(1<<11)) | (value<<11)) //CLK
- #define DOUT(value) (rGPGDAT = (rGPGDAT & ~(1<<7)) | (value<<7)) //MOSI
- #define AD_CS(value) (rGPGDAT = (rGPGDAT & ~(1<<10)) | (value<<10)) //AD_CS
- /************AD的初始化程序**************************
- GPG11-----CLK GPG7----MOSI
- GPG10-----AD_CS GPG1-----MISO
- GPG3----ECO
- ******************************************************/
- void AD_Init(void)
- {
- rGPGCON&=(~((3<<2)|(3<<14)|(3<<20)|(3<<22)|(3<<6)));
- rGPGCON|=(0<<2)|(1<<14)|(1<<20)|(1<<22)|(0<<6); //GPG7,10,11设置成输出,GPG1设置成输入
- rGPGUP&=(~((1<<1)|(1<<7)|(1<<10)|(1<<11)|(1<<3))); //只使能GPG1,7,10,11的上拉,做基本IO口
- }
- void delay_AD(unsigned int N)
- {
- while(N--);
- }
- unsigned short Read_AD(unsigned char ADchannel)
- {
- unsigned int i;
- unsigned short ADC=0;
- ADchannel<<=4; //XXXX 0000,按照格式要求 ,12bits,MSB先入
- while(!(rGPGDAT&0x0008)); //GPG3----ECO如果是低电平,继续,这里一定要加上,不然可能会出现极大的跳变的现象
- CLK(0);
- AD_CS(0);
- for(i=0;i<12;i++)
- {
- if(rGPGDAT&0x0002) ADC|=0x0001;//判断接收GPG1的是否为1
- if(ADchannel&0x80)
- DOUT(1); //向AD发送数据
- else DOUT(0);
- CLK(1);
- delay_AD(30);
- CLK(0);
- delay_AD(30);
- ADchannel<<=1;
- ADC<<=1;
- }
- AD_CS(1);
- ADC>>=1;
- return ADC; //12位精度
- }
#include "2440addr.h"
#include "AD.h"
#define CLK(value) (rGPGDAT = (rGPGDAT & ~(1<<11)) | (value<<11)) //CLK
#define DOUT(value) (rGPGDAT = (rGPGDAT & ~(1<<7)) | (value<<7)) //MOSI
#define AD_CS(value) (rGPGDAT = (rGPGDAT & ~(1<<10)) | (value<<10)) //AD_CS
/************AD的初始化程序**************************
GPG11-----CLK GPG7----MOSI
GPG10-----AD_CS GPG1-----MISO
GPG3----ECO
******************************************************/
void AD_Init(void)
{
rGPGCON&=(~((3<<2)|(3<<14)|(3<<20)|(3<<22)|(3<<6)));
rGPGCON|=(0<<2)|(1<<14)|(1<<20)|(1<<22)|(0<<6); //GPG7,10,11设置成输出,GPG1设置成输入
rGPGUP&=(~((1<<1)|(1<<7)|(1<<10)|(1<<11)|(1<<3))); //只使能GPG1,7,10,11的上拉,做基本IO口
}
void delay_AD(unsigned int N)
{
while(N--);
}
unsigned short Read_AD(unsigned char ADchannel)
{
unsigned int i;
unsigned short ADC=0;
ADchannel<<=4; //XXXX 0000,按照格式要求 ,12bits,MSB先入
while(!(rGPGDAT&0x0008)); //GPG3----ECO如果是低电平,继续,这里一定要加上,不然可能会出现极大的跳变的现象
CLK(0);
AD_CS(0);
for(i=0;i<12;i++)
{
if(rGPGDAT&0x0002) ADC|=0x0001;//判断接收GPG1的是否为1
if(ADchannel&0x80)
DOUT(1); //向AD发送数据
else DOUT(0);
CLK(1);
delay_AD(30);
CLK(0);
delay_AD(30);
ADchannel<<=1;
ADC<<=1;
}
AD_CS(1);
ADC>>=1;
return ADC; //12位精度
}
1.上面的程序是参考51的一个例程仿写的,但是51上没有EOC的反馈的连接,我刚开始也没有接,但是读取的数据一直在0和读取数据之间跳变,而且有时候读取的数据还挺奇怪一直怀疑是时序的同步问题,所以我后来加上了EOC的连接,顺利解决的此事,读取数据还算比较稳定。