基于CC2530-ADC采集特别坑
写篇缘由
博主是一个非常懒的人,能不关注就不用关注,哈哈哈哈。
参加职业技能大赛,而我是组里负责单片机部分,往年是只有CC2530这种单片机 。 而今年是有CC2530 +(新增的STM32的Lora和NB-iot)。
暴躁脾气的小哥
特多东西要学 ,分配时间不当,导致后期才开始苦练CC2530,开始把CC2530的功能逐个啃。
给定自己实现一个功能,Zigbee +光敏二极管 采集(ADC值 和 电压值)数据发送到串口。
平时练习都是这么个习惯,先查看单片机数据手册的ADC相关部分,例程怎么设置寄存器,闭着眼睛写代码,逐步调试,我尝试着把例程的模块功能移植到我的项目工程。(失败)
尴尬的事情开始发生了
我TM直接使用完整的例程项目,得到的结果也不是正确的。(失败)
什么是ADC(简单讲 模拟量–> 数字量)
将时间上连续变化的模拟量转化为脉冲有无的数字 量,这一过程叫数字化,实现数字化的关键设备是ADC。
ADC:数模转换器,将时间和幅值连续的模拟量转化为时间和幅值离散的数字量,A/D转换一般要经过采样、保持、量化、编码4个过程。
CC2530的A/D转换位数(注意这里)
TI提供的CC2530的A/D转换位数是8,10,12,14, 但转换的实际有效位ENOB只有7,9,10,12(不包括: 符号位、最后1位精度损失位)。
数字转换结果可以获得,且结果总是驻留在ADCH和ADCL寄存器组合的MSB(高位)段
CC2530内部ADC各精度对应位(没问题)
在此我们选用实际有效12位
下图是从CC2530的中文手册里截出来,细品,您细品,是不是数据手册表达得有点问题(红色部分是我修正的内容),
初始化ADC相关寄存器
我们这里以 光敏二极管 为例子,采集ADC引脚P0^0,12位精度
1.设置IO口
P0^0 设置为 外设功能、输入引脚、模拟引脚
2.置参考电压,分辨率 通道 启动转换
通道0 512抽取率(12位精度) 参考电压AVDD5(3.3V)
void initial_AD()
{
//设置IO口
P0SEL|=(1<<0); //P0^0外设引脚
P0DIR&=~(1<<0); //P0^0为输入引脚
APCFG|=0x01; //P0^0模拟引脚
//ADCIF = 0; //清除中断标志位
//设置参考电压,分辨率 通道 启动转换
ADCCON3=0xB0; //1011 0000 通道0 512抽取率 参考电压AVDD5,3.3V
}
功能部分
1.判断是否转换完成
2.获取AD值
3.处理AD值
处理AD部分
1. 例程项目(带错误)
uint getTemperature(void){
unsigned int value; //存储AD值
AdcValue = 0;
ADCCON3|=0x3E; // 使用1.25V内部电压,12位分辨率,AD源为:片内温度传感器
ADCCON1|=0x40; //开启单通道ADC
while(!(ADCCON1&0x80)); //等待AD转换完成
value = ADCL >> 2; //ADCL寄存器低2位无效
value |= (((uint)ADCH) << 6);
return value*0.0629-303.3; //根据AD值,计算出实际的温度
}
ADCL和ADCH都是8位,
按照上面算法计算12位分辨率得出 Value 的值是 2^13=8192 比正常值大了一倍。()
错误在 ADCL应该往右移3位,这里却少移1位,导致后面ADCH的位数只能整体向左挪一位。
2. 书本(带错误)
可怕的是书本也是按照这种算法写,得出的值大一倍。
3. 博主(验证过程)
首先让光敏二极管尽量接近最大值,直接把光敏二极管短接了
从上串口调试助手中能看到,得出的值接近8192,实锤,上述算法是有误的。
/*************************************************************************************************/
下面开始更正错误
12位精度的ADC_H(7)和ADC_L(5)的高低位(橙色区域表示有效)
大家动手指头亲自数一下有效是哪几位。
处理方法:
低位:ADCL>>3 去掉低4位包括(精度损失位和无效位)
高位:( ( ADCH<<1 ) >>1 ) (稳起见去掉符号位)
串口助手中可以看出AD值在 2^12=4096之间 ,说明获取的AD值没问题,加上转换电压公式,可以精准算出当前测量的电压值。
完整项目代码
#include "iocc2530.h"
unsigned char AD_data[]="0000-->";
unsigned char V_data[]="00000";
unsigned int adcvalue=0; //ADC值
unsigned int result=0; //电压值
/**********************/
void uart_senString(unsigned char *str); //发送字符串
void uart_senbit(unsigned char bit); //发送字符
void delay(unsigned int tt);
void uart_init();
void Timeinit();
void initial_AD();
/**********************/
void main()
{
CLKCONCMD &=~0x40; //切换系统时钟源为32M晶振
while(CLKCONSTA & 0x40);//等待32M外部晶振稳定
CLKCONCMD &=~0x47; //设置系统主时钟频率为32M
Timeinit(); //初始化定时器
uart_init(); //初始化串口
initial_AD(); //初始化AD
while(1)
{
while(!(ADCCON1&0x80));//等待转换完成
//获取AD值
adcvalue=ADCL>>3;
adcvalue|=(unsigned int)(ADCH<<1>>1) <<5;
AD_data[0]=adcvalue/1000%10+0x30;
AD_data[1]=adcvalue/100%10+0x30;
AD_data[2]=adcvalue/10%10+0x30;
AD_data[3]=adcvalue%10+0x30;
//获取电压值
result=33000*adcvalue/40950; //AD值转换成电压
V_data[0]=(result/1000%10)+0x30;
V_data[1]='.';
V_data[2]=(result/100%10)+0x30;
V_data[3]=(result/10%10)+0x30;
V_data[4]=(result%10)+0x30;
uart_senString("ADC值:");
uart_senString(AD_data); //ADC值发送到PC端
uart_senString("电压值:");
uart_senString(V_data); //电压值发送到PC端
uart_senString("\r\n");
delay(8000);
delay(8000);
ADCCON3=0xB0; //再次启动转换
}
}
//中断服务函数
#pragma vector=T1_VECTOR
__interrupt void Time1()
{
T1STAT &= ~0x01;
}
//串口接收服务函数
#pragma vector=URX0_VECTOR
__interrupt void uartIE()
{
}
void initial_AD()
{
//设置IO口
P0SEL|=(1<<0); //外设功能
P0DIR&=~(1<<0); //输入
APCFG|=0x01; //配置模拟IO
//设置参考电压,分辨率 通道 启动转换
ADCCON3=0xB0; //1011 0000 通道0 512抽取率 参考电压AVDD5(3.3V)
}
void Timeinit()
{
//系统晶振32M
T1CC0H =0x61;
T1CC0L =0xA8; //定时0.1秒
T1CTL =0x0E; //分频系数是128,模模式
T1CCTL0 |=0x04; //通道0比较模式
T1IE=1; //使能定时器中断
T1OVFIM=1; //使能定时器溢出中断
EA=1; //总中断使能
}
void uart_init()
{
//初始化引脚
P0SEL |=0x0C; //串口外设
//设置串口波特率
U0BAUD =59;
U0GCR =8;
//设置串口控制器和串口通讯
U0UCR |=0x80; //清除和控制
U0CSR |=0xC0; //串口状态和使能
//清除中断标志位
URX0IF =0;
UTX0IF =0;
//使能中断
URX0IE =1; //串口接收中断
EA=1;
}
void uart_senbit(unsigned char bit)
{
U0DBUF=bit;
while(!UTX0IF);
UTX0IF=0;
}
void uart_senString(unsigned char *str)
{
while(*str !='\0')
{
uart_senbit(*str++);
}
}
void delay(unsigned int tt)
{
while(tt--);
while(tt--);
while(tt--);
while(tt--);
}
最后提一下本书好多错误
来源:oschina
链接:https://my.oschina.net/u/4268886/blog/4311383