最*做单片机小东西的总结 (STC12C5A60S2)

发布于:2021-07-25 13:30:41

我做的是用 STC12C5A60S2+Nokia5110+DS18B20+DHT21+光敏电阻+NRF42L01 测量温度,然后经过无线传输再显示的小东西。


有快一周的时间被DS18b20折腾着,主要是因为时序不正确。在Keil中模拟(好吧,新手不会有Protel仿真),延时什么的都对,就是初始化失败。求助Google,才知道STC12是1T的单片机,拥有比以往更快的计算速度。所以延时函数要重新写。恩,后来还有温度表的问题,显示乱码,不过换了一个就不乱码了,现在还没弄懂原理是什么。




之前的小数对照表,不过一直有乱码的问题。



//小数位对照表
//uchar code df_Table[] = {0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9};


现在用的小数对照表:



unsigned char code wendu[]="0123456789"; //利用一个温度表解决温度显示乱码

DS18B20的主要函数:





// 初始化DS18B20

unsigned char Init_DS18B20()
{
uchar status;
DQ = 1 ;
Delay(60);
DQ = 0 ;
delay500us();
DQ = 1 ;
Delay(60);
status = DQ ;
Delay(120);
//Delay(100);
return status;
}

//读一个字节

unsigned char ReadOneByte()
{
uchar i=0, dat = 0;
DQ = 1;
Delay(1);
for(i = 0;i < 8;i++)
{
DQ = 0;
dat >>=1;
Delay(2);
DQ = 1;
Delay(2);
if(DQ)
dat |= 0x80;
Delay(60);//延时>45us
DQ = 1;
}
return (dat);
}

//写一个字节

void WriteOneByte(uchar dat)
{
char i=0 ;
for(i = 0;i < 8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay(1);
Delay(60);
DQ = 1;
dat >>= 1;
Delay(1);
}
}

//读取温度值

unsigned int Read_Temperature()
{
unsigned char a=0,b=0;
int t=0;
float tt=0;
if (1 == Init_DS18B20()) DS18B20_IS_OK = 0;
else
{
WriteOneByte(0xCC);
WriteOneByte(0x44);
Init_DS18B20();
Delay(100);
WriteOneByte(0xCC);
WriteOneByte(0xBE);
Delay(100);
Temp_Value[0] = ReadOneByte();
Temp_Value[1] = ReadOneByte();
t=Temp_Value[1];

t=(t<<8)|Temp_Value[0];//两个字节合成一个整型变量
tt=t*0.0625; //得到真实的十进制温度数,因为DS18B20可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度
t=tt*10+0.5; //放大十倍,这样做的目的将小数点后第一位也转换为可显示数字,同时进行一个四舍五入操作。
DS18B20_IS_OK = 1;

}
return (t);
}



DS18B20的难点就是时序新手很难把握,而且我用的单片机是STC 1T 的单片机。推荐使用 “单片机小精灵” 这个软件,可以根据你用的单片机的类型,自动生成延时函数。




接下我要研究的是光敏模块,不过学校的实验室里只有光敏电阻模块,连型号都不知道,获取的值是Vin的值。STC12C5A60S2 这个型号的单片机在 P1 口自带A/D转换,只要添加该型号的头文件,然后调用函数就可以了。




代码如下:



void Delay_ADC(unsigned int n)
{
uint x;

while (n--)
{
x = 5000;
while (x--);
}
}


/*----------------------------
Get ADC result
ch = 2
----------------------------*/
unsigned char GetADCResult(unsigned char ch) //有参数输入 通道几 0-7 P1^0----P1^7
{
//ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
//打开电源 设定转换速度 0-7 路任意一路 启动AD转换

_nop_(); //Must wait before inquiry //延时4个时钟 重要!
_nop_();
_nop_();
_nop_();

while (!(ADC_CONTR & ADC_FLAG));//Wait complete flag //等待AD转换结束标志位置1
ADC_CONTR &= ~ADC_FLAG; //Close ADC //清除 AD 转换结束标志位

return ADC_RES; //Return ADC result //返回 ADC 数据
}


/*----------------------------
Initial ADC sfr
//P1^0 口为AD 输入
----------------------------*/
void Init_ADC()
{ //0000 0000
P1ASF = 0x20; //Open 8 channels ADC function //P1^0 置为 模拟功能 8路都可以作为AD输入
ADC_RES = 0; //Clear previous result // 清除AD转换结果寄存器之前的转换数据
ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
Delay_ADC(2); //ADC power-on and Delay_ADC //初次打开ADC电源 要等待
}

/*------------函数说明--------------------------------
函数功能: 读取 计算*均值后的AD 结果
函数参数: chn:0-7 AD 通道 N :采集多少次AD 计算*均值
返回值 : ad值0-255 AD_Result=AD_Result*5/256; // 计算实际电压值

程序示例:
uint ad_result; //定义一个 读取ad转换结果
ad_result=ADC_N(5,50); // P1^5 采集50次AD结果
------------------------------------------------------*/

unsigned char ADC_N(unsigned char chn,unsigned char N) //采集N次然后取*均值 通道几 采集次数
{
unsigned char i;
unsigned int adc_tem=0;

for(i=N;i>0;i--)
{
adc_tem+=GetADCResult(chn);
}
adc_tem/=N; //adc_tem=adc_tem/N 赋值符合运算

return adc_tem; //返回
}


值得注意的是在 ADC_N()这个函数返回的 adc_tem 并不是最终值。要进行计算才可以得到光敏电阻端的电压 Vin。同时光敏电阻的阻值并不是随光照强度线性变化的,所以如果想得到光照强度的值的话要进行给为复杂的变换,或者换光敏模块。


这几天我在写DHT21的驱动,感觉还是在时序方面出现了问题。网上的例程全都是在12T单片机,而我用的是1T的单片机。



未完待续~~


还有最难得NRF24L01在等着我呢。










???????????????????????????????????2013年12月7日???????????????????????????????














相关推荐

最新更新

猜你喜欢