不管怎样,还是在高手的帮助下完成了前面的硬件部分,现在进行ZigBee的心电AD采集和转换。需要把ZigBee重新拾起来。
首先明确下目标和思路吧,目标是将模拟心电信号通过AD转换,变为数字信号,再用ZigBee传输出来。思路是利用Zstack协议栈,来写程序,通过ADC触发DMA,触发事件,将数据传输到串口或者直接从无线发送出去。
首先是ADC的配置,要配置就必须了解ADC的几个寄存器了。
包括:ADCCFG,ADCCON1,ADCCON2,ADCCON3,ADCH和ADCL
cc2430的ADC可以使用多达八个ADC输入引脚,要配置一个端口0引脚为一个ADC输入,ADCCFG寄存器相应的位置1,这个寄存器选择端口0引脚为非ADC输入。在使用ADC时,通过在ADCCFG寄存器的初始化代码中设置所需的位,ADCCFG寄存器的设置将覆盖P0SEL的设置。
接下来就是3个控制寄存器,ADCCON1是EOC-ST-STSEL[1:0]-RCTRL[1:0]-保留(11),其中EOC当被ADCH和ADCL被读取后才清零。ST表示开始转换,设置成1后,转换完成了会清零。STSEL表示启动转换的选择,00为外部触发,01为全速转换,10为定时器1的通道0的比较事件,11表示ST为1;低4位不涉及,可以全部置1.
ADCCON2,SREF[1:0]-SDIV[1:0]-SCH[3:0],SREF用于设置参考电压,00为内部参考电压,01为AIN7上的外部参考电压,10为AVDD_SOC引脚的电压,11为AIN6和AIN7的差分输入电压。SDIV表示抽取率,决定了采样时间和分辨率。SCH表示序列通道选择。
ADCCON3类似ADCCON2,用于额外采样。
其次,怎样写程序是AD工作,并且将数据读出来,用数字量表示。
这一步是关键,心电的ADC采样到底怎么来设置才能读出数据呢。得一步一步试试。
参照晚上的一些心电程序:http://blog.csdn.net/ohexiwei/article/details/8013570
差不多能知道配置过程,经过一些尝试我的初步配置过程如下:
static uint8 adcRef;
static int16 reading = 0;
void HalAdcInit (void)
{
#if (HAL_ADC == TRUE)
adcRef = HAL_ADC_REF_AVDD;
#endif
}
uint16 HalAdcseriesRead (uint8 channel, uint8 resolution)
{
uint8 i, resbits;
uint8 adcChannel = 1;
/*
* If Analog input channel is AIN0..AIN7, make sure corresponing P0 I/O pin is enabled. The code
* does NOT disable the pin at the end of this function. I think it is better to leave the pin
* enabled because the results will be more accurate. Because of the inherent capacitance on the
* pin, it takes time for the voltage on the pin to charge up to its steady-state level. If
* HalAdcRead() has to turn on the pin for every conversion, the results may show a lower voltage
* than actuality because the pin did not have time to fully charge.
*/
if (channel < 8)
{
for (i=0; i < channel; i++)
{
adcChannel <<= 1;
}
}
/* Enable channel */
ADCCFG |= adcChannel;
/* Convert resolution to decimation rate */
switch (resolution)
{
case HAL_ADC_RESOLUTION_8:
resbits = HAL_ADC_DEC_064;
break;
case HAL_ADC_RESOLUTION_10:
resbits = HAL_ADC_DEC_128;
break;
case HAL_ADC_RESOLUTION_12:
resbits = HAL_ADC_DEC_256;
break;
case HAL_ADC_RESOLUTION_14:
default:
resbits = HAL_ADC_DEC_512;
break;
}
/* writing to this register starts the extra conversion */
ADCCON3 = channel | resbits | adcRef ;
ADCCON1 |= HAL_ADC_STSEL_ST;
ADCCON1 |= HAL_ADC_START;
/* Wait for the conversion to be done */
while (!(ADCCON1 & HAL_ADC_EOC));
/* Disable channel after done conversion */
ADCCFG &= (adcChannel ^ 0xFF);
/* Read the result */
reading = (uint16)ADCL;
reading |=(uint16)(ADCH << 8);
/* Treat small negative as 0 */
/*if (reading < 0)
reading = 0;*/
switch (resolution)
{
case HAL_ADC_RESOLUTION_8:
reading >>= 8;
break;
case HAL_ADC_RESOLUTION_10:
reading >>= 6;
break;
case HAL_ADC_RESOLUTION_12:
reading >>= 4;
break;
case HAL_ADC_RESOLUTION_14:
default:
reading >>= 2;
break;
}
return ((uint16)reading);
}
讲一下我的配置过程吧:首先是参考电压,选择一般网上程序都用的HAL_ADC_REF_AVDD,什么意思,就是外部的一个参考电压,这个电压加在引脚:AVDD_SOC上,我看了一下我的板子,刚好这个脚是接在3.3的电源电压上。接下来是分辨率/抽取率选择14位的,对于新手总是觉得越大越好,通道我选择了0通道。然后是ADCCON1进行控制了,就两个语句ADCCON1 |= HAL_ADC_STSEL_ST;ADCCON1 |= HAL_ADC_START;这两个语句就是开启转换的一个命令,接下来是
/* Wait for the conversion to be done */
while (!(ADCCON1 & HAL_ADC_EOC));
/* Disable channel after done conversion */
ADCCFG &= (adcChannel ^ 0xFF);
/* Read the result */
reading = (uint16) (ADCL);
reading |= (uint16) (ADCH << 8);
等待转换结束,读取数据。好了加电调试,有数据出来了,不过问题也来了,出来的数据不对,数据都是10000以上的,
对照数据手册,可以知道,电压值对应从ADCH和ADCL读出来的数据。如下:
这就奇怪了,最大才8191,刚开始以为我以为是reading的数据类型问题,我将reading统统改成uint16,还是一样,都会超过8191,也就是意味着这个电压是个负值,可是怎么可能呢,我加的一直是正电压(这里注意了一下,我用信号发生器产生信号,一定要加一个正偏置的电压,否则输出会有负值,这个新手不太注意,负值大了会把管脚烧坏),所以还是各种不解。继续分析吧从每个配置开始,首先我不确定的是VREF,这里的VREF我纠结了好久,数据手册里面也没有再提到。后来才知道,这个VREF就是对应ADCCON2和ADCCON3寄存器中所说的参考电压。我对寄存器改了好几次,改成内部参考电压,AIN7引脚输如的外部电压,差分方式没试,都不对,都还是负值,大于8191。又查了数据类型的定义,cc2530的定义如下:
/* ------------------------------------------------------------------------------------------------
* Types
* ------------------------------------------------------------------------------------------------
*/
typedef signed char int8;
typedef unsigned char uint8;
typedef signed short int16;
typedef unsigned short uint16;
typedef signed long int32;
typedef unsigned long uint32;
typedef unsigned char bool;
typedef uint8 halDataAlign_t;
很基本的,都对。接下来再看看分辨率,这时我想起了,一个帖子cc2430和cc2530的不同:http://blog.csdn.net/xukai871105/article/details/7318886
里面讲到了cc2530和2430,ADC分辨率虽然有14位的选项,但是硬件上其实没有达到这个精度和水平,所以软件配置都是12最高了,那么就对了,我一直配置的是14位,但是数据读出来是12位的,怪不得老是大很多,2位刚好是4倍,我给一个1.5v的电压应该是4000多的值,却返回16000多的,这不是刚好4倍,终于找到根源了,两天了。。。。
立马我把配置改成12位的,果然,数据稳定了,而且都在0-8191之间了。加上方波,出现了高低的正常波形数据。。。。!!!感动的啊,我终于自己也解决了个问题了。接下来我想验证一下这个14位和12位的关系,我将配置改成14位,然后将读出来的数据右移2位,读数据,果然啊,和12位一样了,稳定!
总算是把问题解决了。
next,加上心电的波形再试试。后面再加上自己的帧格式,就能传输心电波形了哈!