📄 temp_adc_student.c
字号:
#include <c8051f000.h>
#include <stdio.h>
#define ON 1
#define OFF 0
#define XTLVLD_BIT 0x80 // OSCXCN.7 晶体振荡器有效标志
#define TC_20MS 18432 // 定时器在 11.0592MHz/12时对应于
// 20ms的嘀答数
sbit rd = P1^7;
sbit re = P1^5;
sbit wr = P1^6;
sbit addr0 = P1^0;
sbit addr1 = P1^1;
sbit addr2 = P1^2;
sbit addr3 = P1^3;
sbit addr4 = P1^4;
sbit data0 = P2^0;
sbit data1 = P2^1;
sbit data2 = P2^2;
sbit data3 = P2^3;
sbit lcd_en = P3^0;
//--------------------------------------------------------------------
// 函数原型
//--------------------------------------------------------------------
void sysclk_init (void);
void xbar_init (void);
void ADC_init (void);
void ADC_enable (void);
void Timer3_init (void);
void ADC_isr (void);
void write (int addr, int datain);
unsigned int read();
void delay(int time_10ms);
//--------------------------------------------------------------------
// 全局变量
//--------------------------------------------------------------------
long temperature; // 以百分之一度表示的温度值
unsigned idata temp[16]; // 温度采样值的循环缓冲区
int temp_ptr; // 指向 temp[]的指针
int temp_int; // 温度值的整数部分
int temp_frac; // 温度值的小数部分(以百分之一度为单位)
int n,m,l; //延时程序中用
//--------------------------------------------------------------------
// 主程序
//--------------------------------------------------------------------
void main (void)
{
unsigned int temp1,temp2,xor1,wei1,wei2,temp_wei,i;
WDTCN = 0xde; // Disable watchdog timer
WDTCN = 0xad;
sysclk_init (); // 初始化振荡器
xbar_init (); // 初始化交叉开关和GPIO
Timer3_init (); // 初始化定时器3为 20ms 溢出
ADC_init (); // 初始化 ADC 的输入为温度传感器
ADC_enable (); // 允许 ADC转换结束中断
temperature = 0L;
temp_ptr = 0;
lcd_en=0;
write(1,0);
EA =1 ; // 允许中断
temp2=read();
while (1)
{
temp1=read();
if (temp1!=temp2)
{
xor1=temp1^temp2;
delay(10);
temp2=read();
if (temp1==temp2)
{
wei1=xor1%2;
temp_wei=temp2;
if(wei1!=0)
{
wei2=temp_wei%2;
if(wei2==0)
{i++;
if(i%2==0) EA=0;
if(i%2!=0) EA=1; } //处理KEY1
}
xor1>>=1;
wei1=xor1%2;
if(wei1!=0)
{
temp_wei>>=1;
wei2=temp_wei%2;
if(wei2==0)
{ } //处理KEY2
}
xor1>>=1;
wei1=xor1%2;
if(wei1!=0)
{
temp_wei>>=2;
wei2=temp_wei%2;
if(wei2==0)
{ } //处理KEY3
}
xor1>>=1;
wei1=xor1%2;
if(wei1!=0)
{
temp_wei>>=3;
wei2=temp_wei%2;
if(wei2==0)
{ } //处理KEY4
}
}
}
}
}
// 将器件配置为使用外部 CMOS 时钟。
void sysclk_init (void)
{
WDTCN = 0xde; // 禁止看门狗定时器
WDTCN = 0xad;
OSCXCN = 0x65; // 启动外部振荡器// 对于11.0592MHz的晶体,允许SYSCLK/1
while ( (OSCXCN & XTLVLD_BIT) == 0 ){}// 等待外部振荡器起动
OSCICN = 0x88; // 选择外部振荡器作为系统时钟// 禁止内部振荡器
}
// 配置交叉开关和 GPIO 端口
void xbar_init (void)
{
XBR0 =0x10 ;
XBR1 =0x00 ;
XBR2 =0x40 ; // 允许交叉开关和弱上拉
// PRT0CF |= 0x10; // 允许P0口的所有输出为弱上拉;// 让交叉开关将这些引脚配置为输入
PRT1CF |= 0xff; // P1.6 is push-pull
PRT2CF |= 0xff; // P1.6 is push-pull
P1 |= 0xa0;
}
// 配置 A/D 转换器使用定时器3溢出为转换启动源,并在转换完成时产生中断
void ADC_init (void)
{
ADCEN = 0; // 禁止 ADC
REF0CN =0x07 ; // 允许温度传感器,片内偏置发生器和偏置输出缓冲器
AMX0SL =0x08 ; // 选择温度传感器为ADC多路开关的输出
ADC0CF =0x61 ; // ADC 转换时钟 = sysclk/8// 对11.0592MHz,GAIN = 2x
ADC0CN =0xc5 ; // 禁止ADC,低功耗跟踪方式,// ADC 由定时器3溢出启动,数据左对齐
}
// 允许 ADC;定时器3溢出启动转换;允许ADC中断
void ADC_enable (void)
{
ADCEN =1 ; //允许 ADC
EIE2 |=0X02 ; //允许ADC中断(正常优先级)
}
// 配置定时器3为自动重装载方式,定时间隔为 20ms(不产生中断)
void Timer3_init (void)
{
TMR3CN = 0; // 停止定时器3,清除TF3,使用SYSCLK/12作为时基
TMR3RLH = 0xff & ((-TC_20MS) >> 8);// 初始化重载值
TMR3RLL = 0xff & (-TC_20MS);
TMR3H = 0xff; // 立即重装载
TMR3L = 0xff;
EIE2 =0x00 ; // 禁止定时器3中断
TMR3CN |=0X04 ; // 启动定时器3
}
// ADC 转换结束 ISR
// 在此我们读 ADC 采样值,将其放入到16个采样值的缓冲区内,求所有采样值的平均值
// 并将其转换为以百分之一摄氏度为单位的温度值
void ADC_isr (void) interrupt 15
{
int i; // 循环计数器
long temp_temp; // 临时温度值
ADCINT =0 ; // 清除ADC转换结束中断标志
temp_temp =ADC0H*256+ADC0L; // 装入16位ADC结果
temp[temp_ptr] = temp_temp; // 加到缓冲区中
temp_ptr++;
temp_ptr = temp_ptr % 16; // 回绕缓冲区指针
temp_temp = 0L;
for (i=0; i<16; i++)
{
temp_temp = temp_temp + temp[i]; // 累加采样值,以便求均值
}
temp_temp =temp_temp/16 ; // 总和/16,求得平均值
// 至此,temp_temp 中为16个采样值得平均值。
//现在我们需要将其转换为以百分之一摄氏度表示的温度值。
//
// 在左对齐方式,ADC 产生的代码(CODE)与输入电压成正比:
// CODE = Vin * Gain / Vref * 2^16
//
// 温度传感器产生的电压(Vtemp)与以摄氏度表示的绝对温度(Temp)成正比:
// Vtemp = 2.86mV/C * Temp + 0.776V
//
// 结合这两个方程,我们可以将输出码(左对齐)与输入温度的关系表示为:
// CODE = (2.86mV/C * Temp + 0.776V) * Gain / Vref * 2^16
//
// 解上面的方程求Temp:
// CODE = 2.86mV/C * Temp * Gain/Vref * 2^16 + 0.776V * Gain/Vref * 2^16
// Temp =(CODE-(0.776V * Gain/Vref * 2^16))/(2.86mV/C * Gain/Vref * 2^16)
//
// 可以表示为:
// Temp = (CODE - K1) * K2
//
// 其中 K1 = 0.776 * Gain/Vref * 2^16
// K2 = 1/(2.86mV/C * Gain/Vref * 2^16)
//
// 对于 Vref = 2.4V 和 Gain = 2,
// K1 = 32,932 = 0xa58c
// K2 = 480 / 2^16 – 我们在所有计算中保持该值为480,在最后除以2^16。420=0x01a4
temp_temp =temp_temp-0xa58c ; // 将偏差校正到 0度, 0V
temp_temp =temp_temp*0x01e0 ; // 2.5mV/摄氏度
temp_temp = temp_temp * 100; // 显示结果,以百分之一摄氏度表示
temperature = temp_temp >> 16; // 除以 2^16
temperature=temperature-122;
//补写输出部分程序,将以百分之一度表示的温度值转换成两个十进制数,整数部分和小数部分
write(1,temperature%10);
delay(100);
write(2,temperature/10%10);
delay(100);
write(7,3);
write(3,temperature/100%10);
write(4,temperature/1000%10);
}
void write (int addr, int datain)
{
char pp;
PRT2CF |= 0xff;
pp=addr;
pp|= 0xA0;
P1 =pp;
P2=datain;
wr=1;
wr=0;
}
unsigned int read()
{
unsigned int data_rd;
PRT2CF &= 0xf0;
P2=0xff;
rd=0;
data_rd=P2;
data_rd &=0x0f;
rd=1;
PRT2CF |= 0xff;
return data_rd;
}
void delay(int time_10ms)
{
for (n=0;n<=time_10ms;n++)
{
for(m=0;m<=10;m++)
{
for(l=0;l<=80;l++) ;
}
}
}
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -