(急!!!)ds18b20时序问题
帮我调下ARM+DS18b20时序,我调了半天调不出来。晶振11.0592。控制器LPC2131,串口和中断不用看了。谢谢!
程序:
#include "..\\basescr\\config.h"
#include "stdio.h"
#define DS1820_DQ 1<<7 //DQ脚接P0.2
#defineUART_BPS115200// 串口通讯波特率
int8 time0_flag=0;
//延时函数
void delay(uint8 i)
{
int j,k;
for(j=i;j>0;j--)
for(k=500;k>0;k--);
}
void DelayNl (uint32 dly)
{
uint32 i;
for ( ; dly>0; dly--)
for (i=0; i<5000; i++);
}
/*
*********************************************************************************************************
** 函数名称 :UART0_Init()
** 函数功能 :串口初始化,设置为8位数据位,1位停止位,无奇偶校验,波特率115200。
** 入口参数 :无
** 出口参数 :无
*********************************************************************************************************
*/
void UART0_Init (void)
{
uint16 Fdiv;
U0LCR = 0x83;// DLAB=1,允许设置波特率
Fdiv = (Fpclk / 16) / UART_BPS;// 设置波特率
U0DLM = Fdiv / 256;
U0DLL = Fdiv % 256;
U0LCR = 0x03;
}
/*
*******************************************************************************************************
** 函数名称 :UART0_SendByte()
** 函数功能 :向串口发送字节数据,并等待数据发送完毕。
** 入口参数 :data要发送的数据
** 出口参数 :无
*******************************************************************************************************
*/
void UART0_SendByte (uint8 data)
{
U0THR = data;
while ((U0LSR & 0x40) == 0);// 等待数据发送完毕
}
/*中断服务程序*/
void __irq IRQ_Timer0 (void)
{
time0_flag=1;
T0IR = 0x01;/* 清除中断标志*/
VICVectAddr = 0x00;/* 通知VIC中断处理结束*/
}
/*定时0.5秒钟*/
void Timer0_Init(void)
{
IRQEnable();/* IRQ中断使能*/
/* 定时器0初始化 */
T0TC = 0;/* 定时器设置为0*/
T0PR = 0;/* 时钟不分频*/
T0MCR = 0x03;/* 设置T0MR0匹配后复位T0TC,并产生中断标志*/
T0MR0 = Fpclk; /*0.5秒钟定时*/
T0TCR = 0x01;/*启动定时器 */
/* 设置定时器0中断IRQ */
VICIntSelect = 0x00;/* 所有中断通道设置为IRQ中断*/
VICVectCntl0 = 0x20 | 0x04;/* 设置定时器0中断通道分配最高优先级*/
VICVectAddr0 = (uint32)IRQ_Timer0;/* 设置中断服务程序地址 */
VICIntEnable = 1 << 0x04;/* 使能定时器0中断*/
}
//初始化函数
void Init_DS18B20(void)
{
uint8 x;
IO0DIR=DS1820_DQ; //做数据数出口
IO0SET = DS1820_DQ; //DQ复位
delay(1); //稍做延时
IO0CLR = DS1820_DQ; //将DQ拉低
delay(80); //精确延时 大于 480us
IO0SET = DS1820_DQ; //拉高总线
delay(6);
IO0DIR=IO0DIR & ~(DS1820_DQ);//做数据数入口
delay(6);
if(IO0PIN & DS1820_DQ==0x0080) //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
x=1;
else
x=0;
delay(6);
}
//读一个字节
uint8 ReadOneChar(void)
{
uint8 i=0;
uint8 dat = 0;
for (i=8;i>0;i--)
{
IO0DIR=DS1820_DQ; //做数据数出口
IO0CLR = DS1820_DQ; // 给脉冲信号
dat>>=1;
IO0SET = DS1820_DQ; // 给脉冲信号
IO0DIR=IO0DIR & ~(DS1820_DQ);//做数据数入口
delay(1);
if((IO0SET & DS1820_DQ)==0x80)
{
dat|=0x80;
}
delay(4);
}
return(dat);
}
//写一个字节
void WriteOneChar(uint8 dat)
{
uint8 i=0;
uint8 temp;
IO0DIR = DS1820_DQ; //DQ为输出口
for (i=8; i>0; i--)
{
IO0CLR = DS1820_DQ;
temp=dat&0x01;
if(temp==1) //按位写入
IO0SET=DS1820_DQ;
else if(temp==0)
IO0CLR=DS1820_DQ;
delay(5);
IO0SET = DS1820_DQ;
dat>>=1;
}
}
//读取温度值
float ReadTemperature()
{
uint8 a=0;
uint8 b=0;
uint16 t=0;
float tt=0;
Init_DS18B20(); //调用初始化函数
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
Init_DS18B20(); //调用初始化函数
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
a=ReadOneChar(); //读取温度的低8位
b=ReadOneChar(); //读取温度的高8位
t=b;
t<<=8;
t=t|a; //得到温度值
tt=t*0.0625;
return(tt);
}
//主函数
int main()
{
float temp=0;
char str[30];
int i,n;
/*管脚设置*/
PINSEL0 = 0x00000005;// 设置I/O连接到UART0
PINSEL1= 0x00000000;
IO0DIR = DS1820_DQ; //初始化为数出口
Timer0_Init();
UART0_Init();
DelayNl(10);
while(1)
{
if(time0_flag==1)
{
time0_flag=0;
temp=ReadTemperature();//读取温度值
n=sprintf(str, "Now Temp is:%.3f ℃\n", temp);
i=0;
while(i<n)
{
temp=str[i];
UART0_SendByte(temp);
i++;
}
}
}
// return 1;
}
[解决办法]
你的delay 有没有用定时器测过延时时间? 以前我用C给51写的程序也没问题的
[解决办法]
1-wire,单总线对时序的要求很高,高电平持续时间、低电平持续时间、延时时间不能简单估计,必须很精确。所以最好先用示波器看一下每段波形是否完整,是否符合要求。
[解决办法]
现在才反应过来,你是不是直接将51下的delay给移植过来了?同样是11.0529MHz的晶振,对于ARM和51,这个delay产生的真正延时也是相差极大的。你要么就看编译之后的delay对应的汇编指令,要么就用示波器确认delay实际的延时,要么就改用定时器进行真正的延时,总之,这个delay的内在本质,你需要重新认识。这个也是你这次碰到问题的关键。