jsbyysheng 发表于 2016-3-7 15:04:38

[使用实例] 树莓派驱动AD7606数据采集模块—SPI接口使用手记

本帖最后由 ky123 于 2018-3-2 09:25 编辑

      最近做项目,尝试着使用Raspberry Pi2来进行开发。Raspberry Pi2还是挺强大的,只是感觉可用的IO口很少。。项目中需要用到ADC模块,就去淘宝上淘一个安富莱德AD7606,感觉做工挺不错的还。不过价格也是贵哈,120大洋买的。

      AD7606是8路、16位的AD,真双极性-5~+5或者-10~+10,采样率为200ksps(不可设定),可以选择使用并行模式、字节模式以及SPI模式。考虑到树莓派可怜的IO口数量,妥妥的选择用SPI模式。


      板子默认是上图左边的并行模式,因此拿到手之后需要改动用一下电阻到右边的样子。再详细的资料大家可以去淘宝搜一下,上面讲的很详细。废话不多说,下面上接线图。

       AD7606是带了数字滤波器的,可以通过OS1~OS3来配置,这里我接到了固定电平(000,不滤波)上。有需要的话也可以接到gpio上,我发的驱动程序里面已经预留好了接口。然后rage口是配置量程的,我也接的的固定电平(选择了-5~+5),同样的也可以接在gpio上。AD7606的时序还是很简单的,是标准的SPI接口。由于其所有配置都通过管教的电平来完成,所用的SPI只有SCLK和MISO。
      下图即为AD7606串行模式下的时序图。转换时序选择了在转换后读取,比较方便配置(比较好写^_^),然后是下面的SPI
转换时序图

通信时序图
的时序图。SPI的通信有4种模式,如下图所示,对比可以知道是第二种,即CPOL = 1, CPHA = 0。根据linux/spi/spidev.h中的定

义可知为/*----- SET SPI MODE -----
    SPI_MODE_0 (0,0)         CPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge, output data (change) on falling edge
    SPI_MODE_1 (0,1)         CPOL = 0, CPHA = 1, Clock idle low, data is clocked in on falling edge, output data (change) on rising edge
    SPI_MODE_2 (1,0)         CPOL = 1, CPHA = 0, Clock idle high, data is clocked in on falling edge, output data (change) on rising edge
    SPI_MODE_3 (1,1)         CPOL = 1, CPHA = 1, Clock idle high, data is clocked in on rising, edge output data (change) on falling edge
    spi_mode = SPI_MODE_0;应该为SPI_MODE_2。然而,当我在wiringPi的官网查看reference时却发现只提到有以下两个函数:int wiringPiSPISetup (int channel, int speed) ;
int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ;并不能设置模式啊!!!这和说好不一样啊,坑爹的wiringPi为毛没有把mode接口留出来呢。不甘心之下就去github上查阅了wiringPiSPI.h的源文件,发现了猫腻:#ifdef __cplusplus
extern "C" {
#endif

int wiringPiSPIGetFd   (int channel) ;
int wiringPiSPIDataRW    (int channel, unsigned char *data, int len) ;
int wiringPiSPISetupMode (int channel, int speed, int mode) ;
int wiringPiSPISetup   (int channel, int speed) ;

#ifdef __cplusplus
}
#endif原来如此,mode还是可选的,只是作者没有提而已。。再查阅一下wiringPiSPISetup函数原型可知,其默认选择了mode0,所以我们在使用时应该使用wiringPiSPISetupMode函数。
       接下来直接上驱动的核心代码:(参考安富莱提供的8051程序进行移植)uint8_t ADC_val;

void AD7606_Init(){
      AD7606_IOSet();
      AD7606_SetDF(0);               //default:OS2 OS1 OS0 = 000
      AD7606_SetInputRange(0);         //default:range = -5 ~ +5
      AD7606_Reset();
}

//hook function,used to set input range.
void AD7606_SetInputRange(int _ucRange){
      
}
//hook function,used to set digital filter.
void AD7606_SetDF(uint8_t _ucMode){
      
}
//reset function
void AD7606_Reset(){
      digitalWrite(CS , HIGH);
      digitalWrite(CVAB , HIGH);
         /* AD7606 is high level reset,at least 50ns */
      digitalWrite(RST, LOW);
      //delayMicroseconds(1);
      digitalWrite(RST, HIGH);
      //delayMicroseconds(1);
      digitalWrite(RST, LOW);
}

void AD7606_IOSet(){
      pinMode(RST , OUTPUT);
      pinMode(CVAB, OUTPUT);
      pinMode(CS, OUTPUT);
      pinMode(BUSY, INPUT);
      pullUpDnControl(BUSY, PUD_UP);
      digitalWrite(RST, LOW);
      digitalWrite(CS , HIGH);
      digitalWrite(CVAB , HIGH);
}

void AD7606_StartConv(){
      /* Conv in rising edge,at least 25ns*/
      digitalWrite(CVAB, LOW);
      //delayMicroseconds(1);
      digitalWrite(CVAB, HIGH);
}
//Software Poll
bool AD7606_StartADC(){      
      if (digitalRead(BUSY) == 0){
                digitalWrite(CS, LOW);
                if (wiringPiSPIDataRW (SPI_CHANNEL_0, ADC_val, CH_NUM * 2) == -1){
                printf("SPI failure: %s\n", strerror(errno));
                }
                digitalWrite(CS, HIGH);
                AD7606_StartConv();                        
                while(digitalRead(BUSY) == 0);
                return true;
      }
      else{
                printf("Value is not ready: %s\n", strerror(errno));
                return false;
      }
}这里为需要软件控制数字滤波器以及采样范围的留下了两个hook function,可以自己扩展。然后上电的reset函数,根据手册reset的时间不应少于50ns,而Raspberry Pi2的gpio口电平转换最快是4MHz左右,因此无需额外的延时。在AD7606_StartConv函数中进行了采样结果转换开始的操作。根据手册,我将CVA和CVB口并联起来,给一次信号接足够。按照安富莱提供的资料的说法,CVAB最好接到有pwm输出能力的口上,所以我选择了gpio1,不过后来发现没什么特别之处,换成别的口应该也没什么问题。最后就是AD7606_StartADC函数,由于本次的项目需要用到软件查询的方式采样,所以这里我仅仅写了软件查询,没有写中断的方式。根据函数可以知道,采样的第一组数据是无效的。最终的采样结果是8个16位的数,我保存在了一个extern变量extern uint8_t ADC_val;中,每个结果占数组的两个位置。因此,在调用AD7606_StartADC()后,从ADC_val数组中即可方便的获得采样结果。
       接下来就是上电实测。使用稳压电源输出3.0000V,稳压电源本身测得输出为3.0037V,万用表测得为3.007V。使用


AD7606的通道1进行采样,通道2~7接地,通道8悬空,得到如下的测量结果:

第一组数据根据驱动文件的驱动方式可知是无效的。观察第二组之后的数据可知采集得到的数据是有效的。至此,驱动完毕。
**** Hidden Message *****

jsbyysheng 发表于 2016-3-8 22:54:46

沙发自己坐

yu0405jie 发表于 2016-3-16 22:05:55

看着不错,顺便问一下,最高采样率实际可到多少?

bubuxindong 发表于 2016-3-20 10:30:00

mark            

jsbyysheng 发表于 2016-3-20 19:28:29

yu0405jie 发表于 2016-3-16 22:05 static/image/common/back.gif
看着不错,顺便问一下,最高采样率实际可到多少?

应该是可以到200Ksps

qqq1234567 发表于 2016-3-31 23:15:19

請問,可以附上實際 rpi 連結 ad7606 module 的圖嗎?
對硬體很不熟悉,希望可以對照著做。
謝謝~~

jsbyysheng 发表于 2016-4-2 12:50:36

qqq1234567 发表于 2016-3-31 23:15 static/image/common/back.gif
請問,可以附上實際 rpi 連結 ad7606 module 的圖嗎?
對硬體很不熟悉,希望可以對照著做。
謝謝~~...

文章中已经给了连接图。

bajonetty 发表于 2016-4-11 18:27:35

厲害!
正好需要此類經驗,謝謝!

bajonetty 发表于 2016-4-15 15:32:52

樓主有個問題!

Raspberry Pi2的GPIO 28,29在哪里?
你確定有麽?

GPIO28,29衹有在PI 的Reversion 2.0才有啊!!

jsbyysheng 发表于 2016-4-18 11:58:29

bajonetty 发表于 2016-4-15 15:32 static/image/common/back.gif
樓主有個問題!

Raspberry Pi2的GPIO 28,29在哪里?


我用的就是2B+
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: [使用实例] 树莓派驱动AD7606数据采集模块—SPI接口使用手记