师姐(博士)反向规划了ADS7841芯片。为了测验其稳定性和精度,所以帮助写了这个驱动程序。开端是师兄用FPGA写的,但读出来的数据距离太大,所以我就用430单片机帮助搞了一个!但这个程序调试的并不顺畅,几乎便是苦楚,我昨天中午和晚上都没吃饭!首要碰到I/O口坏的状况,还有便是这个芯片的 DATASHEET关于读数的阐明是错的,害人不浅!据datasheet解说是等候busy信号为低才开端读数,其实这个时分现已晚了,会漏掉一位。一切上面这些问题我是凭借逻辑剖析仪看出来的,把抓出来的时序一点点的剖析,总算发现了读数方面DATASHEET的缝隙。还有便是她没提写数据和读数据别离应该在时钟的什么沿触发。真实让人抑郁~!~正常应该在下降沿写指令,上升沿读数据!
折腾了一天才有成果,假如不是逻辑剖析仪的帮助,我估量死都不知道怎样死的。。
好了,状况阐明晰,下面是代码部分。
*****************************************************************************
** 函数原型:unsigned int ADS7841_Read_Data(unsigned char Channel);
** 功 能:SPI总线的A/D ADS7841 驱动程序
** 进口参数:unsigned char Channel 表明挑选读取通道
** 出口参数:unsigned int 回来所读获得12位数据。
** 说 明:ADS7841为12位A/D,先对其进行设置:数据位D0—D7,其间D0—D1是
** 设置ADC的功耗形式,D2是模仿输入通道设置,H为4个单通道,L为两个
** 差分输入,D3为mode,当mode(pin)接地时为12位采样方法,接高电平时
** mode为1时8位收集,为0时12位收集,D4—D6为输入通道挑选,D7为开端位
** 作 者: 深思的鱼
** 日 期: 2007年11月06日
**—————————————————————————–
** 修 改 人:
** 日 期:
*******************************************************************************/
#include <msp430x14x.h>
#define uint unsigned int
#define uchar unsigned char
#define ADS_S 0x80 //指令开端位
#define ADS_MODE 0x08 //形式挑选。MODE端挑选直接接高电平,此位不必设置
#define ADS_S_D 0x04 //输入方法挑选
#define ADS_POWER 0x00 //是否答应掉电
#define DIR_CS P3DIR|=BIT0
#define ADS_CS_1 P3OUT|=BIT0
#define ADS_CS_0 P3OUT&=~BIT0 //片选
#define ADS_DIR_IN P3DIR|=BIT1 //端口输出形式
#define ADS_DIN_1 P3OUT|=BIT1 //指令写入AD
#define ADS_DIN_0 P3OUT&=~BIT1
#define ADS_DIR_OT P2DIR&=~BIT0 //端口为输入形式
#define ADS_CLK_DIR P4DIR|=BIT4 //端口为输出形式
#define ADS_CLK_1 P4OUT|=BIT4 //时钟置1
#define ADS_CLK_0 P4OUT&=~BIT4 //时钟置0
#define DIR_BUSY P4DIR&=~BIT0
//#define DATA_IN ((P4IN>>2 & 0x01)
#define DATA_IN (P2IN & 0x01)
#define BUSY_IN (P4IN & 0x01) //读输入数据
void Check_busy(void);
void SPI_WR(uchar DATA);
void Init_Port(void);
void delay(uint temp);
uint ADS7841_Read_Data(uchar Channel);
uint temp_DATA[100];
void delay(uint temp1)
{
int i;
for(i=temp1;i>0;i–)
{
;
}
}
uint ADS7841_Read_Data(uchar Channel) //Channel=0:CH0;1:CH1;2:CH2;3:CH3;
{
uint ADCResult=0;
uchar i,ADS_CHANNEL;
uint TempBit =0;
uchar COMMAND=0;
switch (Channel)
{
case 0:ADS_CHANNEL=0x10;break; //通道挑选
case 1:ADS_CHANNEL=0x50;break;
case 2:ADS_CHANNEL=0x20;break;
case 3:ADS_CHANNEL=0x60;break;
default:ADS_CHANNEL=0x10;break;
}
COMMAND=(ADS_S|ADS_CHANNEL|ADS_S_D|ADS_POWER);
ADS_CLK_0;
ADS_DIN_0; ///DIN先置0
ADS_CS_0; //;片选信号
//SPI_WR(COMMAND); //SPI总线写指令子程序
//ADS_DIR_IN; //端口界说为输出形式,上升沿发送,下降沿承受
for(i=0;i<8;i++)
{
ADS_CLK_1;
if( (COMMAND & 0x80) ==0x80)
{
ADS_DIN_1; //写入指令
}
else
{
ADS_DIN_0;
}
COMMAND<<=1; //左移
delay(5);
ADS_CLK_0;
delay(5); //模仿SPI串行接口 发送数据
}
delay(5);
ADS_CLK_0;
Check_busy();
//delay(5);
for(i=0;i<12;i++)
{ //上升沿读出数据
ADS_CLK_0;
delay(4);
if( DATA_IN==0x01 )
{
TempBit=1;
}
else
{
TempBit=0;
}
ADS_CLK_1;
ADCResult=((ADCResult<<1)|TempBit); //模仿SPI串行接口,接纳数据
delay(5);
}
ADS_CLK_0;
for(i=0;i<4;i++)
{
ADS_CLK_1;
delay(5);
ADS_CLK_0;
delay(5);
}
ADS_CS_1; //屏蔽片选
return ADCResult;
}
void Check_busy(void)
{
int temp;
//DIR_BUSY; //端口设置为输入方法
ADS_CLK_1;
temp=BUSY_IN;
ADS_CLK_0;
while( (temp&0x01)==0) //检测到高电平就开端读数。。否则会丢一位
{
ADS_CLK_1; //读端口状况….
temp=BUSY_IN;
//delay(5); //
ADS_CLK_0;
}
//
/* do
{
ADS_CLK_0; //读端口状况….
temp=BUSY_IN;
delay(5); //
ADS_CLK_1;
}while((temp&0x01)!=0); //高位为1为忙信号*/
}
void SPI_WR(uchar DATA)
{
uint i;
ADS_DIR_IN; //端口界说为输出形式,上升沿发送,下降沿承受
for(i=0;i<8;i++)
{
ADS_CLK_1;
if( (DATA & 0x80) ==0x80)
{
ADS_DIN_1; //写入指令
}
else
{
ADS_DIN_0;
}
DATA<<=1; //左移
ADS_CLK_0;
delay(5); //模仿SPI串行接口 发送数据
}
delay(5);
ADS_CLK_0;
}
void Init_Port(void)
{
P3SEL=0X00;
P4SEL=0X00;
ADS_DIR_IN;
ADS_DIR_OT;
ADS_CLK_DIR;
DIR_BUSY;
DIR_CS;
ADS_CLK_0;
//delay(5);
ADS_CS_1;
// ADS_CLK_1;
}
void main(void)
{
WDTCTL = WDTPW+WDTHOLD; //关看门狗
Init_Port(); //端口初始化
uint flag=0;
uint i;
while(1)
{
for(i=0;i<5;i++)
{
temp_DATA[i]=ADS7841_Read_Data(0);
delay(10);
}
flag=1;
}
}