最近打算做俱arduino的“高精度”數控電源,但arduino的ADC只有10位,精度遠遠不夠,網上亂看,發現了便宜、好用的12位雙通道ADC模塊-TM7705,模塊的價格只要6元錢。
網上找了一圈,只找到了一個很遠古的spi讀寫庫。我的板子已經打好,spi接口不太方便用,就參考了網上的資料,順帶學習了tm7705的數據手冊,寫了個軟spi的讀定程序。程序加了詳細的注釋,結合數據手冊,其實這個程序也是一個學習根據手冊時序,自己寫外設驅動例子。搞懂了,以后碰到沒有現成庫的外設(如LCD、DAC、ADC等等),也可以自己寫,不用求人了。
剛學習arduino,寫得不規范,僅供參考。
tm7705_module.png (124.31 KB, 下載次數: 131)
下載附件
2021-2-2 20:19 上傳
/*軟件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);
}
|