#include"STC15.H" //单片机寄存器定义
#include"Binary.H" //提供二进制输入
#include<intrins.h> //提供_nop_函数
#include<math.h> //提供fabs浮点数绝对值转换函数
#include"NTC3435.c" //提供NTC查询表
#include"nRF24L01.C"//提供nRF24L01驱动
//初始化变量
unsigned int code Voltage_BandGap_ROM _at_ 0x1ff7; //8K程序空间的MCU
//unsigned int code Voltage_BandGap_ROM _at_ 0xe7f7;//58K程序空间的MCU
//运行变量
unsigned int ADC_DATA; //读取到的ADC转换值
unsigned int ADC_BandGap; //读取的BandGap转换值
float VCC_Voltage; //计算得到的VCC电压值,单位mV
float NTC_Voltage; //计算得到的NTC分压电压值,单位mV
float NTC_Temperature; //查表计算得到的NTC对应温度值,单位℃
unsigned long NTC_R_Comp=0; //待对比的电阻值,单位十倍欧姆
//运行计数
unsigned int T0_Cnt=0; //定时器0周期计数
//运行标志位
bit En_ADC_Value=0; //ADC转换值标志 0:无效 1:有效
bit Do_VCC_Voltage_Flash=0; //电源电压值刷新动作标志位 1:执行一次更新
/************************************************************
名称:基于NTC热敏电阻和nRF24L01的无线温度计(测量部分)
平台:STC15W408AS,频率:22.1184MHz
测试:IAP15W4K58S4,频率:22.1184MHz
简介:测量部分使用NTC-MF52-103/3435热敏电阻进行温度采集,
通过读取单片机内部BandGap电压得到准确的电源电压和外部电压,
使用查表方法得到对应的最靠近的温度值,处理并显示。
无线部分采用2.4G载波的nRF24L01模块进行数据传输。
精度说明:设此采集过程中,影响采集精度的唯一因素为ADC对电压的分辨率,
若排除高精度分压电阻的误差,则在5V稳定电压供电条件下,可得到
能识别的NTC电阻变化跨度为97.7517106549(十倍欧姆),由于NTC电阻
阻值是随温度非线性变化的,则固定分辨率下,不同温度值附近精度不同,
本次设计使用的单片机具有10位ADC,最小分辨率为4.8828mV,
计算得到20℃定点温度下的理论跨度误差约为1.521190476%。
注意:程序下载时请选中:在程序区的结束处添加重要测试参数
程序编写:凌净清河
硬件制作:凌净欣羽
文稿排版:凌净欣羽
日期:2019年2月18日
声明:相关程序参考宏晶科技例程
所属:新矿城学习基地#2019
************************************************************/
void delay(unsigned long i) //延时函数,调用此函数进行一段时间的非精准延时
{
while(i--);
}
void VCC_Voltage_Read() //调用此函数更新电源电压值,存储在VCC_Voltage变量中,该函数改变ADC的设置
{
P1ASF=B00000000; //不设置P1ASF,以便上电读取BandGap电压的ADC转换值
ADC_CONTR=B10000000; //开启ADC电源,设置转换速度540时钟周期,清空转换标志位,停止转换,模拟通道选择P1^0
ADC_RES=0; //清除结果寄存器
ADC_RESL=0; //清除结果寄存器
CLK_DIV&=B11011111; //ADC_RES[7:0]存放高8位ADC结果,ADC_RES[1:0]存放低2位ADC结果
//PADC=1; //设置A/D转换中断优先级为最高
ADC_CONTR|=0x08; //开始转换
_nop_();
_nop_();
_nop_();
_nop_(); //按照例程延时4个周期
while(!En_ADC_Value); //等待转换结束
En_ADC_Value=0; //清除标志位
ADC_BandGap=ADC_DATA; //保存BandGap的ADC转换值
VCC_Voltage=Voltage_BandGap_ROM*1023.0/(float)ADC_BandGap;//电源电压值计算
}
void NTC_Voltage_Read() //调用此函数更新NTC电压值,存储在NTC_Voltage变量中,该函数改变ADC的设置
{
P1ASF=B00100000; //NTC接在P15
ADC_CONTR=B11100101; //开启ADC电源,设置转换速度90时钟周期,清空转换标志位,停止转换,模拟通道选择P1^5
ADC_RES=0; //清除结果寄存器
ADC_RESL=0; //清除结果寄存器
CLK_DIV&=B11011111; //ADC_RES[7:0]存放高8位ADC结果,ADC_RES[1:0]存放低2位ADC结果
//PADC=1; //设置A/D转换中断优先级为最高
ADC_CONTR|=0x08; //开始转换
_nop_();
_nop_();
_nop_();
_nop_(); //按照例程延时4个周期
while(!En_ADC_Value); //等待转换结束
En_ADC_Value=0; //清除标志位
NTC_Voltage=Voltage_BandGap_ROM*(float)ADC_DATA/(float)ADC_BandGap;//NTC分压电压计算
}
void Timer0Init(void) //2毫秒@22.1184MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x33; //设置定时初值
TH0 = 0x53; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void sys_init() //系统初始化函数
{
P0M1=0x00;P0M0=0x00;
P1M1=0x00;P1M0=0x00;
P2M1=0x00;P2M0=0x00;
P3M1=0x00;P3M0=0x00;
P4M1=0x00;P4M0=0x00;
P5M0=0x00;P5M1=0x00;
Timer0Init(); //定时器0初始化
nRF24L01_IO_init(); //nRF24L01通信线电平初始化
nRF24L01_SetMode_Tx(); //nRF24L01发送模式初始化
EA=1; //开总中断
ET0=1; //开定时器0中断
EADC=1; //开ADC转换中断
VCC_Voltage_Read(); //读取电源电压
}
void main() //主函数
{
sys_init(); //系统初始化
while(1) //主函数大循环
{
NTC_Voltage_Read(); //读取NTC的分压值(P15上的模拟电压)
NTC_R_Comp=100000*NTC_Voltage/(VCC_Voltage-NTC_Voltage);//计算待对比的NTC阻值,单位十倍欧姆
NTC_Temperature=NTC_103_3435_Compare(NTC_R_Comp);//查表计算NTC对应的温度值
//无线发送
if(NTC_Temperature>0)
{
Transmit_Buff[0]=1;//数据为正标志
}
else
{
NTC_Temperature=(float)fabs((double)NTC_Temperature); //取温度绝对值
Transmit_Buff[0]=0;//数据为负标志
}
Transmit_Buff[1]=((unsigned int)NTC_Temperature)/100; //温度值百位
Transmit_Buff[2]=((unsigned int)(NTC_Temperature)%100)/10; //温度值十位
Transmit_Buff[3]=((unsigned int)NTC_Temperature)%10; //温度值个位
Transmit_Buff[4]=((unsigned long)(NTC_Temperature*10000)%10000)/1000; //温度值小数1位
Transmit_Buff[5]=((unsigned long)(NTC_Temperature*10000)%1000)/100; //温度值小数2位
Transmit_Buff[6]=((unsigned long)(NTC_Temperature*10000)%100)/10; //温度值小数3位
Transmit_Buff[7]=((unsigned long)(NTC_Temperature*10000))%10; //温度值小数4位
Transmit_Buff[8]=((unsigned int)VCC_Voltage)/1000; //电压值千位
Transmit_Buff[9]=((unsigned int)(VCC_Voltage)%1000)/100; //电压值百位
Transmit_Buff[10]=((unsigned int)(VCC_Voltage)%100)/10; //电压值十位
Transmit_Buff[11]=((unsigned int)VCC_Voltage)%10; //电压值个位
Transmit_Buff[12]=((unsigned long)(VCC_Voltage*100)%100)/10; //电压值小数1位
Transmit_Buff[13]=(unsigned long)(VCC_Voltage*100)%10; //电压值小数2位
nRF24L01_SendData(Transmit_Buff); //使用nRF24L01发送温度数据
if(Do_VCC_Voltage_Flash)
{
Do_VCC_Voltage_Flash=0; //条件动作清零
VCC_Voltage_Read(); //读取电源电压
}
delay(100000); //周期循环延时
}
}
void T0() interrupt 1 //定时器0中断服务函数
{
T0_Cnt++; //周期增加
if(T0_Cnt==1000) //定时2秒
{
T0_Cnt=0; //清空计数器
Do_VCC_Voltage_Flash=1; //条件动作执行
}
}
void ADC() interrupt 5 //AD中断服务函数
{
ADC_CONTR&=!0x10; //清除ADC中断标志,例程
ADC_DATA=(ADC_RES<<2)|ADC_RESL; //10位ADC结果拼接
En_ADC_Value=1; //ADC转换值有效标志
}
#include"iostm8s103f2.h"
#include"Init.c" //系统初始化函数
#include"nRF24L01.C"//提供nRF24L01驱动
//运行数组
unsigned char Display[8]={10,10,10,10,10,10,10,10};//用于显示的每一位数值,对应段选数组中的相应位
unsigned char duan[11]={0xeb,0x09,0xe5,0xad,0x0f,0xae,0xee,0x89,0xef,0xaf,0x04};//数码管段选数组 数字0~9和符号"-"
/*
段码对应表,仅适用本电路
8 4 2 1 8 4 2 1
7 6 5 4 3 2 1 0
A E D H C G F B
1 1 1 0 1 0 1 1 0
0 0 0 0 1 0 0 1 1
1 1 1 0 0 1 0 1 2
1 0 1 0 1 1 0 1 3
0 0 0 0 1 1 1 1 4
1 0 1 0 1 1 1 0 5
1 1 1 0 1 1 1 0 6
1 0 0 0 1 0 0 1 7
1 1 1 0 1 1 1 1 8
1 0 1 0 1 1 1 1 9
0 0 0 0 0 1 0 0 -
*/
//运行变量
unsigned char pointpositionA=3;//温度显示的小数点位置,从0到3
unsigned char pointpositionB=4;//电压显示的小数点位置,从4到7
//运行计数
unsigned int TIM4_cnt=0;//TIM4定时器周期计数
/************************************************************
名称:基于NTC热敏电阻和nRF24L01的无线温度计(接收显示部分)
平台:STM8S103F2P6,HSI:16MHz,CPUDIV:8
资源:Flash:4K RAM:1K
简介:测量部分使用NTC-MF52-103/3435热敏电阻进行温度采集,
通过读取单片机内部BandGap电压得到准确的电源电压和外部电压,
使用查表方法得到对应的最靠近的温度值,处理并显示。
无线部分采用2.4G载波的nRF24L01模块进行数据传输。
程序编写:凌净清河
硬件制作:凌净欣羽
文稿排版:凌净欣羽
日期:2019年2月25日
声明:制作参考龙顺宇《深入浅出STM8单片机入门、进阶与应用实例》
所属:新矿城学习基地#2019
编写中临时记录:
本程序欠缺段选数组,数码管显示函数
数码管计划使用138和双595级联的方式驱动2个4位数码管
一个显示温度,一个显示采集部分的供电电压
还有配套的数据处理语句待编写。
************************************************************/
void delay(unsigned char i) //延时函数,调用此函数进行一段时间的非精准延时
{
while(i--);
}
void SPIsendB(unsigned char dat)//给级联的第一个595写字节
{
unsigned char a;
unsigned int tmp=0;
tmp=dat<<8;
SN74HC595_SRCLK=0;
SN74HC595_RCLK=0;
for(a=0;a<16;a++)
{
if(tmp&0x8000)
{
SN74HC595_SER=1;
}
else
{
SN74HC595_SER=0;
}
tmp<<=1;
SN74HC595_SRCLK=1;
asm("nop");
asm("nop");
asm("nop");
asm("nop");
SN74HC595_SRCLK=0;
}
SN74HC595_RCLK=1;
asm("nop");
asm("nop");
SN74HC595_RCLK=0;
}
void SPIsendA(unsigned char dat)//给级联的第二个595写字节
{
unsigned char a;
unsigned int tmp=0;
tmp=tmp|dat;
SN74HC595_SRCLK=0;
SN74HC595_RCLK=0;
for(a=0;a<16;a++)
{
if(tmp&0x8000)
{
SN74HC595_SER=1;
}
else
{
SN74HC595_SER=0;
}
tmp<<=1;
SN74HC595_SRCLK=1;
asm("nop");
asm("nop");
asm("nop");
asm("nop");
SN74HC595_SRCLK=0;
}
SN74HC595_RCLK=1;
asm("nop");
asm("nop");
SN74HC595_RCLK=0;
}
void smgNum(unsigned char num)//位选函数,配合显示函数使用,选择138译码输出的位
{
switch(num)
{
case 0:SN74HC138_S3=1;SN74HC138_S2=1;SN74HC138_S1=1;break;
case 1:SN74HC138_S3=1;SN74HC138_S2=1;SN74HC138_S1=0;break;
case 2:SN74HC138_S3=1;SN74HC138_S2=0;SN74HC138_S1=1;break;
case 3:SN74HC138_S3=1;SN74HC138_S2=0;SN74HC138_S1=0;break;
case 4:SN74HC138_S3=0;SN74HC138_S2=1;SN74HC138_S1=1;break;
case 5:SN74HC138_S3=0;SN74HC138_S2=1;SN74HC138_S1=0;break;
case 6:SN74HC138_S3=0;SN74HC138_S2=0;SN74HC138_S1=1;break;
case 7:SN74HC138_S3=0;SN74HC138_S2=0;SN74HC138_S1=0;break;
default:SN74HC138_S3=0;SN74HC138_S2=0;SN74HC138_S1=0;break;
}
}
/*
编者按:
在设计连接时,用于显示温度的74HC595的SN74HC595_SER端
接在用于显示电压的595 Q7'端,两个74HC595级联,
我也不知道当时怎么想的,选择如此焊接,
但是既然电路这么做出来了,程序只好照着编了。
*/
void smgdisplay()
{
unsigned char i;
for(i=0;i<4;i++)//温度数据显示
{
if(pointpositionA==i)
{
SPIsendA((duan[Display[i]])|0x10);
}
else
{
SPIsendA(duan[Display[i]]);
}
smgNum(i);//选择相应位
delay(100);
SPIsendA(0x00);//消隐
delay(50);
}
for(i=4;i<8;i++)//电压数据显示
{
if(pointpositionB==i)
{
SPIsendB((duan[Display[i]])|0x10);
}
else
{
SPIsendB(duan[Display[i]]);
}
smgNum(i);//选择相应位
delay(100);
SPIsendB(0x00);//消隐
delay(50);
}
}
void sys_init()//系统初始化
{
asm("sim");
CLK_init(); //HSI初始化,更改分频系数为1
TIM4_init(); //TIM4初始化,定时1ms
asm("rim");
SN74HC595_IO_Define(); //SN74HC595接线定义
SN74HC138_IO_Define(); //SN74HC138接线定义
nRF24L01_IO_Define(); //nRF24L01接线定义
nRF24L01_IO_init(); //nRF24L01通信线初始化
nRF24L01_SetMode_Rx(); //nRF24L01功能初始化:接收模式
}
void main(void)
{
sys_init(); //系统初始化
while(1)
{
if(nRF24L01_ReceiveData()) //如果接收到数据
{
TIM4_cnt=0;
if(Received_Buff[0])//温度为正
{
if(Received_Buff[1]==0)//如果百位为0
{
if(Received_Buff[2]==0)//如果十位为0
{
Display[0]=Received_Buff[3];
Display[1]=Received_Buff[4];
Display[2]=Received_Buff[5];
Display[3]=Received_Buff[6];
pointpositionA=0;
}
else
{
Display[0]=Received_Buff[2];
Display[1]=Received_Buff[3];
Display[2]=Received_Buff[4];
Display[3]=Received_Buff[5];
pointpositionA=1;
}
}
else
{
Display[0]=Received_Buff[1];
Display[1]=Received_Buff[2];
Display[2]=Received_Buff[3];
Display[3]=Received_Buff[4];
pointpositionA=2;
}
}
else
{
Display[0]=11;//负号
if(Received_Buff[1]==0)//如果百位为0
{
if(Received_Buff[2]==0)//如果十位为0
{
Display[1]=Received_Buff[3];
Display[2]=Received_Buff[4];
Display[3]=Received_Buff[5];
pointpositionA=1;
}
else
{
Display[1]=Received_Buff[2];
Display[2]=Received_Buff[3];
Display[3]=Received_Buff[4];
pointpositionA=2;
}
}
else
{
Display[1]=Received_Buff[1];
Display[2]=Received_Buff[2];
Display[3]=Received_Buff[3];
pointpositionA=3;
}
}
Display[4]=Received_Buff[8];
Display[5]=Received_Buff[9];
Display[6]=Received_Buff[10];
Display[7]=Received_Buff[11];
}
smgdisplay();
}
}
#pragma vector=0x19//定时器4中断服务函数
__interrupt void TIM4_UPD_OVF_IRQHandler(void)
{
TIM4_cnt++;
TIM4_SR=0;
if(TIM4_cnt==500)
{
unsigned char i;
TIM4_cnt=0;
for(i=0;i<8;i++)
{
Display[i]=10;
}
}
}
联系客服