打印
[Cortex-M0技术交流]

M058SSAN-DS18B20串口助手显示温度

[复制链接]
1773|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hxjlm|  楼主 | 2015-7-18 12:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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


相关帖子

沙发
lvyunhua| | 2015-7-21 08:28 | 只看该作者
多谢楼主分享!

使用特权

评论回复
板凳
xixi2017| | 2017-9-11 18:57 | 只看该作者
不错,好资料,谢谢。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

14

主题

117

帖子

0

粉丝