基于CC2530-ADC采集特别坑

喜你入骨 提交于 2020-08-13 16:25:18

写篇缘由

博主是一个非常懒的人,能不关注就不用关注,哈哈哈哈。
参加职业技能大赛,而我是组里负责单片机部分,往年是只有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--);
}

最后提一下本书好多错误在这里插入图片描述

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!