本帖最后由 hxjlm 于 2015-7-18 13:12 编辑
延时函数非常重要,温度转换不成功多半是它的问题,搞了两天都没转换出温度,用模拟示波器一看,延时函数用不同的值,误差非常的大,修正后转换出正常温度值,果断分享.项目由:M051 BN初始化项目向导(http://nuvoton-m0.com/code/cn/Init_M051/wiz/index.htm)自动生成;芯片选择M058LBN(LQFP48);CPU时钟-外部4~24MHz;时钟除频1;SysTick使用UCP时钟;UART0外部4~24MHz;除频2;
UART0:6MHz/9600/8/1/N/1
这个是main.c
/**************************************************************************
*程序名称:DS18B20-UART输出PC温度显示实验
*代码说明:DS18B20由串口输出PC串口助手显示温度
*程序编写:本程序由何新建编写
*实 验:hxj于2015.7.18
*实验芯片:MCU-M058SSAN;P0.3(P49)接DS18B20中间脚(P2);P3.0-UART-RXD-5脚接TTL-TXD.P3.1-UART-TXD-10脚接TTL-RXD.TTL-GND-GND
*硬件连接:DS18B20左起1脚_GND-GND。2脚_DATA-M058的P0.3(49)。3脚_VCC-VCC3.3V
*实验结果:DS18B20输出到UART//成功显示温度,小数点后4位
*Library files文件夹必须添加retarget.c文件UART串口与PC通讯才能成功
*串口助手:波特率-9600/数据位-8/校验位-N/停止位-1;接收:文本模式
***************************************************************************/
/* 本程序由 NuSmart 工具自动产生 */
#include <stdio.h>
#include "M051Series.h"
#include "DS18B20.h"
/*-----------------------------------------------------------------*/
/* 初始化系统时钟 */
/*-----------------------------------------------------------------*/
void SYS_Init(void)
{
/* 解锁保护的寄存器 */
SYS_UnlockReg();
/* 使能 XTL12M */
SYSCLK->;PWRCON |= SYSCLK_PWRCON_XTL12M_EN_Msk;
/* 等待时钟稳定 */
SYS_WaitingForClockReady(SYSCLK_CLKSTATUS_XTL12M_STB_Msk);
/* 切换HCLK和SysTick的时钟源 */
SYSCLK->CLKSEL0 = SYSCLK_CLKSEL0_HCLK_XTAL | SYSCLK_CLKSEL0_STCLK_XTAL;
/* 切换IP模块的时钟源 */
SYSCLK->CLKSEL1 = SYSCLK_CLKSEL1_UART_XTAL;
SYSCLK->CLKDIV = (0 << SYSCLK_CLKDIV_HCLK_N_Pos)
| (1 << SYSCLK_CLKDIV_UART_N_Pos)
| (0 << SYSCLK_CLKDIV_ADC_N_Pos);
/* !!! SysTick被设定为来自"XTL12M", 当开始该时钟时,
请不要在SysTick->CTRL中使用SysTick_CTRL_CLKSOURCE_Msk位。*/
/* PLL掉电模式 */
SYSCLK->;PLLCON = 0x0005C22E;
/* 现在可以安全的关闭没使用的时钟了! */
SYSCLK->;PWRCON &= ~(SYSCLK_PWRCON_OSC22M_EN_Msk
| SYSCLK_PWRCON_OSC10K_EN_Msk);
/* 使能外围设备时钟 */
SYSCLK->APBCLK = SYSCLK_APBCLK_UART0_EN_Msk;
/* 重置外围设备 */
SYS->IPRSTC2 = SYS_IPRSTC2_UART0_RST_Msk
| SYS_IPRSTC2_GPIO_RST_Msk;
SYS->IPRSTC2 = 0;
/* 锁定保护的寄存器 */
SYS_LockReg();
}
/*-----------------------------------------------------------------*/
/* 初始化IO引脚 */
/*-----------------------------------------------------------------*/
void IO_Init(void)
{
/* 设定引脚复用功能 */
SYS->;P3_MFP = SYS_MFP_P30_RXD0
| SYS_MFP_P31_TXD0;
}
/*-----------------------------------------------------------------*/
/* 初始化UART0 */
/*-----------------------------------------------------------------*/
void UART0_Init(void)
{
/* UART0设定 */
UART0->BAUD = UART_BAUD_MODE0 | UART_BAUD_DIV_MODE0(6000000, 9600);
_UART_SET_DATA_FORMAT(UART0, UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1);
UART0->FCR = UART_FCR_RTS_TRI_LEV_1BYTE
| UART_FCR_RFITL_1BYTE
| UART_FCR_RX_DIS_Msk;
}
int32_t main(void)
{
SYS_Init();//系统时钟初始化
IO_Init(); //GPIO3.0、3.1初始化
UART0_Init();//UART串口初始化
printf("DS18B20:\n");//串口助手显示
while(1)
{
uint8_t i;
read_temp();//开始转换温度//有此句下面打印语句不工作
for(i=0;i<10;i++)
{
printf("%c ",str);//打印字符串,字符串结尾必须\0
}
delay_ds18b20(10000000);//延时1s
}
}
这个是DS18B20.c
#include "M051Series.h"
#include "DS18B20.h"
uint8_t str[10];//在.h里定义了全局可用变量
/*************************************************************************************
** Function name: delay_us
** Descriptions: 大约2us(晶振为12MHZ)延时子程序
** input parameters: count
** output parameters: 无
** Returned value: 无
*************************************************************************************/
void delay_ds18b20(uint32_t us)
{
uint32_t i;
for(i=1;i<us;i++);
}
/*
void delay_ds18b20(uint32_t us)//这是从mini51芯片移植来的延时函数,误差很大,温度转换不成功
{
SysTick->LOAD = us * CyclesPerUs;
SysTick->VAL = (0x00);
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
//Waiting for down-count to zero
while((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0);
}*/
/***
DS18B20初始化函数
***/
void ds1820reset()
{
uint8_t i;
i = 1;
if (i)
{
DQ = 0; //送出低电平复位信号
delay_ds18b20(1160); //延时至少480us
DQ = 1; //释放数据线
delay_ds18b20(145); //等待60us
i = DQ; //检测存在脉冲
delay_ds18b20(2400); //等待设备释放数据线
}
}
/***
DS18B20读一个字节数据
***/
uint8_t ds1820rd()//读数据
{
uint8_t i=0;
uint8_t dat = 0;
for (i=0; i<8; i++)
{
dat >>= 1;//让从总线上读到的位数据,依次从高位移动到低位?
DQ=1;
delay_ds18b20(1);//1us
DQ = 0;//将总线拉低,要在1us之后释放总线
delay_ds18b20(6); //4us //至少维持了1us,表示读时序开始
DQ = 1;
delay_ds18b20(6);//4us
if (DQ)//控制器进行采样
dat|=0x80;//若总线为1,即DQ为1,那就把dat的最高位置1;若为0,则不进行处理,保持为0
delay_ds18b20(145);//1us //60us
}
DQ=1;
return dat;
}
/*************************************************************************************
DS18B20 写数据
*************************************************************************************/
void ds1820wr(uint8_t dat)//写数据
{
uint8_t i=0;
for (i=0; i<8; i++)
{
DQ = 1;
delay_ds18b20(1); //延时小1us //两次传送间隔大于1us
DQ = 0;
delay_ds18b20(6); //延时小4us
DQ = dat & 0x01; //最低位移出
delay_ds18b20(145); //60us
dat >>= 1; //右移一位
}
DQ = 1;
}
/*************************************************************************************
** Descriptions: 读取温度值并将读到的温度进行处理
*************************************************************************************/
//uint16_t read_temp()//读取温度值并转换
void read_temp()
{
uint16_t temp_value;//小数点前温度值
uint16_t value; //小数点后温度值
uint8_t a,b;
uint8_t mark; //温度正负标志
temp_value = 0;//变量赋予初值
value = 0;
ds1820reset(); //初始化DS18B20
ds1820wr(0xcc);//跳过读序列号
ds1820wr(0x44);//启动温度转换
while(!DQ);//等待转换完成
ds1820reset();
ds1820wr(0xcc);//跳过读序列号 发Skip ROM命令
ds1820wr(0xbe);//发送读取温度命令
a=ds1820rd(); //读取温度小数点后//连续读取两个字节数据 先读出的是低位数据
b=ds1820rd(); //读取温度小数点前//连续读取两个字节数据 后读出的是高位数据
temp_value = ((b<<8)|a);//高低字节组合
if(b &= 0xfc)//判断是正温度还是负温度读数 高8位的前6位是否为1,是为负温度
{//负温度读数求补,取反加1,判断低8位是否有进位
mark=1;
temp_value=(((~temp_value)+1)*0.0625);//求反补1并转换出温度值
value=((~a)+1)&0x0f;//求反补1并取出小数点后4位
value=value*625; //转换出小数点后4位温度值
}
else
{
mark=0;
temp_value=(temp_value*0.0625);//小数点以前的温度数值
value=(a&0x0f)*625;//小数点以后4位数
}
if(mark == 1)//判断是正温度还是负温度读数 正为0;负为1;
{str[0] = '-';}else{str[0] = ' ';}//mark=1输出“-”
str[1] = temp_value/100 + '0';//取出百位转换成ASCII码
if(str[1]=='0'){str[1]=' ';}//如果整数的百位是0,输出空格
str[2] = (temp_value%100)/10 + '0';//取出十位转换成ASCII码输出
str[3] = (temp_value%100)%10 +'0';//取出个位转换成ASCII码输出
str[4] = '.';//输出“.”输出字符串后要加个0,标示字符串输出完
str[5] = value/1000 + '0';//取出小数点后一位转换成ASCII码输出
str[6] = (value%1000)/100 + '0';//取出小数点后两位转换成ASCII码输出
str[7] = ((value%1000)%100)/10 + '0';//取出小数点后三位转换成ASCII码输出
str[8] = ((value%1000)%100)%10 + '0';//取出小数点后四位转换成ASCII码输出
str[9] = '\n';
}
这个是DS18B20.h
#ifndef __DS18B20_H__
#define __DS18B20_H__
extern uint8_t str[10];//全局调用的变量
void delay_ds18b20(uint32_t us);
void ds1820reset(void);
uint8_t ds1820rd(void);
void ds1820wr(uint8_t wdata);
void read_temp(void);
#define DQ P03//P0->;PMD &=~(3UL<<6)//P0.3准双向模式
#endif
|