本帖最后由 wangku001wei 于 2012-10-1 18:56 编辑
首先看原理图 红色代表模拟引脚 绿色代表数字引脚
电路原理图
新使用了一个模拟复用器和8位的电压模数转换器,对应端口为 VRefPort——P5[5]——T_POWER VSignalPort——P5[6]——T_SENSE
模拟复用端口采用了3个通路
采用这种方式的原因是为了降低热敏电阻上采集到的电压误差
根据电流相等,得到公式1
公式1 由公式1,推导,得到公式2,热敏电阻阻值公式:
公式2 注意,我们这个例子中 电压值V2为0 aPort_YAxia 和三轴加速度的一个引脚向量 dPort_AcclControl和三轴加速度的三个控制引脚相连,用于向加速度传感器写入命令 dPort由8个IO口组成,且由于在POSC的端口设置中如果端口的位宽大于1,则在实际分配引脚时,这些端口必须是同一个Px口上的相邻IO口,因此dPort分为了高低各四位的dPort_LSB和dPort_MSB PdPort_LSB 对应P2口的P2[3:0]控制 dPort_MSB 对应P4口的P4[3:0]控制 同样的,反向是因为电路设计为低电平点亮LED,高电平熄灭LED ADC转换器选择了11位精度,连续转换方式,由软件开启ADC转换,时钟为内部804kHz 以上设置可以在引脚分配视图上看出
主函数代码分析 /******************************************************************************************* * 主函数的功能: * 1: 初始化所有的变量 * 2: 关闭LED的灯 * 3: 初始化加速度传感器 * 4: 启动AD转换,读取加速度Y轴方向上的数据 * 5: 测量温度并转换为字符串 * 6: 将字符串转换为光栅像素数组 * 7: 等待摇动. * 8: 以一定速度更新光栅数据 ********************************************************************************/ void main() {
uint8 RasterCount; /*光栅像素数组的索引*/ uint8 RasterLength; /*当前字符串转换为光栅像素数据后的数组长度*/ // 按键的状态 uint8 ButtonPressFlag;
/*初始化硬件*/ CYGlobalIntEnable; /*使能全局中断*/ LEDControlReg_Write(0); /*熄灭LED灯*/ /*控制加速度传感器 ENABLE=1, MODE=1, ST/MODE=LOW */ // #define ACCL_SET_CONTROL ((uint8) 0x06) dPort_AcclControl_Write(ACCL_SET_CONTROL); AMux_1_Start(); /* 使能模拟复用器 */ AcclADC_Start(); /* 使能AD转换 */ VDAC8_1_Start(); /* 使能电压模数转换器 */ // 设置模数转换器的范围 VDAC8_1_SetRange(VDAC8_1_RANGE_1V); // 设置模数转换器的值 VDAC8_1_SetValue(200 );
while(1) { /* 读取按键的状态,当按键状态改变后,改变现实温度的格式,摄氏度或者华氏度 */ /* 栅格化的延时用于放置按键抖动. */ if(SwitchPort_Read() == 1) { if(ButtonPressFlag == 0) { TemperatureModeFlag = TemperatureModeFlag ^ 0x01; ButtonPressFlag = 1; } } else { ButtonPressFlag = 0; }
/* 计算当前温度 */ Thermistor_TemperatureCompute();
/* 将当前温度转换为栅格化像素数组 */ RasterLength = LED_StringProcess(DisplayString);
AMux_1_Select(2); AcclADC_Stop(); AcclADC_Start(); /* 等待挥动开始 */ do { AcclADC_StartConvert(); AcclADC_IsEndConversion(AcclADC_WAIT_FOR_RESULT); }while(AcclADC_GetResult16() > ACCEL_TRIGGER);
/* 在LED 开始显示和开始挥动之间进行延时*/ LED_Delay(INITIAL_DELAY);
/* 将每列光栅数据输送到8位LED上,同时每列光栅数据间进行延时 */
for(RasterCount = 0; RasterCount < RasterLength; RasterCount++) { LED_Delay(RASTER_DELAY); LEDControlReg_Write(DisplayRasterTable[RasterCount]); }
/* 等待这次挥动结束 */ do { AcclADC_StartConvert(); AcclADC_IsEndConversion(AcclADC_WAIT_FOR_RESULT); }while(AcclADC_GetResult16() < (255 - ACCEL_TRIGGER)); } }
关于得到测量温度的函数 Thermistor.c 文件中的 void Thermistor_TemperatureCompute(void)函数
使用了查找表 表中记录了从-40到125摄氏度每隔1摄氏度对应的ADC采样值 整摄氏度之间的值采用线性插值的方法算出 插值计算过程: TempTable_UpperLimit 对应的是表中索引小,温度低而实际值大的 TempTable_LowerLimit 对应的是表中索引大,温度高而实际值小的 ThermistorResistance ADC转换出来的值 Thermistor_Temperature 是最终得到的温度数值,由于要保留1位小数,结果乘以了10 TempTable_Decimal 计算过程中间临时保留的值,或者说是小数部分 插值公式3
公式3 注1由于表是从-40度开始制作的,所以要减去40 由于是从较低的温度开始的,所以要减去1
代码分析 void Thermistor_TemperatureCompute(void) {
int32 ThermistorResistance; /* 计算得到的热敏电阻上的电压数据 */ int16 Thermistor_Temperature; /*计算得到的温度值,由于要保留1位小数,结果乘以了10 */ int Count=0; uint16 ADC_VRef, ADC_VThermistor, ADC_VRefLow = 0; /* ADC采样得到的值 */ long TempTable_UpperLimit, TempTable_LowerLimit; /* 线性插值变量 */ float TempTable_Decimal; /* 计算出的温度值的小数部分 */
/* 启用模拟复用器通道0,并AD采集参考电阻上电压值 */ AMux_1_Select(0); AcclADC_Stop(); AcclADC_Start(); AcclADC_StartConvert(); AcclADC_IsEndConversion(AcclADC_WAIT_FOR_RESULT); ADC_VRef = AcclADC_GetResult16();
/*启用模拟复用器通道1,并AD采集热敏电阻上电压值*/ AMux_1_Select(1); AcclADC_Stop(); AcclADC_Start(); AcclADC_StartConvert(); AcclADC_IsEndConversion(AcclADC_WAIT_FOR_RESULT); ADC_VThermistor = AcclADC_GetResult16();
/* 根据公式2计算得到热敏电阻的阻值 */ ThermistorResistance = (((int32)(ADC_VThermistor - ADC_VRefLow) * (int32)THERM_RREF) / ((int32)(ADC_VRef - ADC_VThermistor)));
/* 得到计算得到的阻值在查找表中的位置*/ for(Count = 0; Thermistor_TempTable[Count] >= ThermistorResistance; Count++);
/* 根据公式3插值计算温度值 */ TempTable_Decimal = 0; TempTable_LowerLimit = Thermistor_TempTable[Count]; TempTable_UpperLimit = Thermistor_TempTable[Count-1];
TempTable_Decimal = ((TempTable_UpperLimit - ThermistorResistance) * 10) / (TempTable_UpperLimit - TempTable_LowerLimit); Thermistor_Temperature = (Count - 40 - 1) * 10 + (TempTable_Decimal);
/* 将整数温度值转换为字符型字符串 */ ThermistorTempToString(Thermistor_Temperature); }
关于将温度数值转换为能够显示的字符串的函数Thermistor.c 文件中的 void ThermistorTempToString(int32 Temperature)函数
代码分析 void ThermistorTempToString(int32 Temperature) { // 分别对应百位 十位 个位 十分位 const uint16 DigitPower[] = {1000, 100, 10, 1}; uint8 i = 0; // 当前的位置 uint8 CurrentDigit; uint8 TempDigit; // 确定该位是否要显示字符的标志变量 uint8 Leading0Flag = 0;
/* 如果设置了华氏度,则进行转换 */ /* 9/5 ~= 461/256, 320 = 32*10 */ if(TemperatureModeFlag == FAHRENHEIT_MODE) { Temperature = ((461 * Temperature) >> 8) + 320; }
/* 如果是负数,则在字符串中添加负号,并保留绝对值 */ if(Temperature < 0) { DisplayString[i++] = '-'; Temperature = -(Temperature); }
/* 对每一位的温度值进行转换,并存入全局变量DisplayString 字符数组中*/ for(CurrentDigit = 0; CurrentDigit < 4; CurrentDigit++) { TempDigit = 0; /* 初始化该为数字为0 */ // 使用循环相减的方式得到该位的实际值,搞不明白为啥不直接除?! while(Temperature >= DigitPower[CurrentDigit]) { TempDigit++; Temperature -= DigitPower[CurrentDigit]; Leading0Flag = 1; } if(CurrentDigit == 2) /* 保证小数点前面至少有个0 */ { Leading0Flag = 1; }
if(Leading0Flag == 1) /* 将当前位数的值转换为字符保存在数组中 */ { DisplayString[i++] = TempDigit + '0'; }
if(CurrentDigit == 2) /* 在个位后面添加个小数点 */ { DisplayString[i++] = '.'; } }
DisplayString[i++] = '\''; /* 如果是华氏度,添加’F’ */ if(TemperatureModeFlag == FAHRENHEIT_MODE) { DisplayString[i++] = 'F'; } else { DisplayString[i++] = 'C'; } DisplayString[i++] = '\0'; /* 字符串的结束字符 */
|