最近打算做俱arduino的“高精度”数控电源,但arduino的ADC只有10位,精度远远不够,网上乱看,发现了便宜、好用的12位双通道ADC模块-TM7705,模块的价格只要6元钱。
网上找了一圈,只找到了一个很远古的spi读写库。我的板子已经打好,spi接口不太方便用,就参考了网上的资料,顺带学习了tm7705的数据手册,写了个软spi的读定程序。程序加了详细的注释,结合数据手册,其实这个程序也是一个学习根据手册时序,自己写外设驱动例子。搞懂了,以后碰到没有现成库的外设(如LCD、DAC、ADC等等),也可以自己写,不用求人了。
刚学习arduino,写得不规范,仅供参考。
/*软件spi 输入双通道12位ADC Tm7705
arduino nano + Tm7705模块。 工具->arduino nano 处理器 -> Atmega328p (old bootloader)
(CS) LE -> PC1(D10)pc1(a1)
(DIN) DIN -> PC2(D11)pc2(a2)
(SCK) CLK -> PC0(D13)PC0(A0)
(DOUT)DOUT -> PC3(D12)PC3(a3)
arduino nano 需要与tm7705板子共地,不然有严重干扰。
*/
//----声明引脚--------------
int SCLK_TM7705 = A0;
int DIN_TM7705 = A2;
int DOUT_TM7705 = A3;
int LE_TM7705 = A1;
//int DRDY_TM7705 = 5; //DRDY既可以专门用1个IO读,也可以读通信寄存器的最高位。此程序采用读寄存器方法,省一个IO口。
unsigned char n, temp1, temp2;
unsigned int V_adc0, V_adc1;
float v0, v1;
int errDRDY = 0;
// ---------------------------------------------------
void write_byte_TM7705(unsigned char dat1) //将数据dat1写入TM7705,CLK下降沿写
{
unsigned char i;
digitalWrite(SCLK_TM7705, 1); //拉高时钟
digitalWrite(LE_TM7705, 0); //片选
delayMicroseconds(1);
for (i = 0; i < 8; i++) //写8位数据
{
digitalWrite(SCLK_TM7705, 0); //下降沿
delayMicroseconds(1);
if (dat1 & 0x80)
{
digitalWrite(DIN_TM7705, 1);
} //先写高位
else
{ //再写低位
digitalWrite(DIN_TM7705, 0);
}
delayMicroseconds(1);
digitalWrite(SCLK_TM7705, 1); //时钟空闲时,置高电平。
delayMicroseconds(1);
dat1 <<= 1; //下一位
}
digitalWrite(SCLK_TM7705, 1); //时钟空闲,高。
digitalWrite(DIN_TM7705, 1); //输入脚,置高。(抗干扰)
digitalWrite(LE_TM7705, 1); //
}
unsigned char read_byte_TM7705() //从TM7705寄存器读8位数据,在DOUT_TM7705上读。
{
unsigned char i, read_dat, dat2 = 0;
digitalWrite(SCLK_TM7705, 1); //时钟空闲,高。
delayMicroseconds(1);
digitalWrite(LE_TM7705, 0); //片选
for (i = 0; i < 8; i++)
{
digitalWrite(SCLK_TM7705, 0); //下降沿
delayMicroseconds(1);
read_dat = digitalRead(DOUT_TM7705);
dat2 = (dat2 << 1) | read_dat; // 高位先读
delayMicroseconds(1);
digitalWrite(SCLK_TM7705, 1); //时钟空闲,高。
delayMicroseconds(1);
}
digitalWrite(SCLK_TM7705, 1); //时钟空闲,高。
digitalWrite(LE_TM7705, 1); //
return dat2;
}
//------------通过读“通信寄存器”的DRDY位是否0,来判断DRDY是否已经就绪------------------
bool DRDY_OK() {
unsigned char rd = 1;
errDRDY = 0;
while (rd) {
write_byte_TM7705(B00001000); //写通讯寄存器下一步读通信寄存器
delayMicroseconds(10);
rd = read_byte_TM7705();
rd = (rd >> 7) & B00000001; //取通讯寄存器第1位(DRDY)
errDRDY++;
delayMicroseconds(1);
if (errDRDY > 1000) {
Serial.println("----errDRDY---");
return 0;
}
}
return 1;
}
//----------通过IO读DRDY电平是否0,判断是否就绪,此程序不用--------------------
/*
bool IO_DRDY_OK() {
unsigned char rd = 1;
errDRDY = 0;
while (rd) {
rd = digitalRead(DRDY_TM7705);
delayMicroseconds(10);
if (errDRDY > 1000) {
Serial.println("----errDRDY---");
return 0;
}
}
return 1;
}
*/
//----------------------------------------------------
/*
在写程序时SCLK管脚的高、低电平的延时都要大于2US,程序流程大致上电40个时钟用于软件复位,
然后发寄存器配置指令,在自校准后需要200MS的延时后才能接收到有效的输出数据,且每次通道
切换都要进行自校准(即每次切换都要等待200MS)。
*/
void TM7705_init(byte channel) //channel1:0 channel2:1
{
char i;
digitalWrite(SCLK_TM7705, 1); //时钟空闲,高。
digitalWrite(DIN_TM7705, 1); //
digitalWrite(DOUT_TM7705, 1); //此脚为arduino读tm7705数据的IO,应该是输入口,pinmode设置为input_pullup,空闲时为高
// digitalWrite(DRDY_TM7705, 1);
//-------------step:1----------------------
for (i = 0; i < 40; i++) //连续40个下降沿
{
digitalWrite(SCLK_TM7705, 0); //下降沿
delayMicroseconds(1);
digitalWrite(SCLK_TM7705, 1); //下降沿
delayMicroseconds(1);
}
delayMicroseconds(1000);
delayMicroseconds(1);
//------------step:2.写时钟寄存器----------------------------------
write_byte_TM7705(0x20); //通道1和2共用(0 0 1 0 0 0 0 0),写通讯寄存器下一步写时钟寄存器
//write_byte_TM7705(0x04); //50HZ(0 0 0 0 0 1 0 0) 若晶振为2.4576MHZ需设置CLKDIV=0,CLK=1
//write_byte_TM7705(0x08); //20HZ(0 0 0 0 1 0 0 0) 若晶振为2MHZ需设置CLKDIV=1,CLK=0
write_byte_TM7705(0x0c); //50HZ(0 0 0 0 1 1 0 0) 若晶振为4.9152MHZ需设置CLKDIV=1,CLK=1,频率50HZ。
//------------step:3.写设置寄存器----------------------------------
write_byte_TM7705(0x10 | channel); //通道1(0 0 0 1 0 0 0 0),写通讯寄存器下一步写设置寄存器
//write_byte_TM7705(0x44); //写入设置寄存器(0 1 0 0 0 1 0 0),自校准模式0 1,1倍增益0 0 0,单极性B/U=1,buf串联设置为0,FSYNC=0;
//write_byte_TM7705(0x40); //写入设置寄存器(0 1 0 0 0 0 0 0),自校准模式0 1,1倍增益0 0 0,双极性B/U=0,buf串联设置为0,FSYNC=0;
write_byte_TM7705(0x44); //写入设置寄存器(0 1 0 0 0 1 0 0),自校准模式0 1,1倍增益0 0 0,单极性B/U=0,buf串联设置为0,FSYNC=0;
delay(200);
}
//-----------------------------------------------------
unsigned int readADC(byte channel) {
unsigned int rd = 0;
// if (IO_DRDY_OK()) {
if (DRDY_OK()) {
write_byte_TM7705(0x38 | channel); //(0b00111000读通道0)
delayMicroseconds(1);
rd = read_byte_TM7705(); //先读高8位
rd = (rd << 8) | read_byte_TM7705(); //再读低8位
delayMicroseconds(1);
return rd;
}
else
{
Serial.println("--errDRDY------");
return -1;
}
}
//-------------------------------------------------
void setup() {
pinMode(SCLK_TM7705, OUTPUT);
pinMode(DIN_TM7705, OUTPUT);
pinMode(DOUT_TM7705, INPUT_PULLUP);
pinMode(LE_TM7705, OUTPUT);
// pinMode(DRDY_TM7705, INPUT_PULLUP);
TM7705_init(0);
delayMicroseconds(50);
TM7705_init(1);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
V_adc0 = readADC(0);
v0 = 5 * (V_adc0 / 65535.0);
Serial.println(V_adc0);
Serial.println(v0, 6);
Serial.println("========");
V_adc1 = readADC(1);
v1 = 5 * (V_adc1 / 65535.0);
Serial.println(V_adc0);
Serial.println(v0, 6);
Serial.println("========");
delay(1000);
}
|