原创 基于ARM单片机的单总线应用

2010-8-16 17:11 3873 14 14 分类: MCU/ 嵌入式

基于ARM单片机的单总线应用


单总线(1-Wire)是美国达拉斯半导体公司的一项专利技术。与目前广泛应用的其他串行数据通信方式不同,它采用单根信号线完成数据的双向传输,具有节省I/O引脚资源、结构简单、成本低廉、便于总线扩展等诸多优点。关于单总线技术及其芯片的介绍,请参考有关资料。


⒈      硬件设计


在我的博文“基于51单片机的单总线”中介绍了采用51单片机、DS18B20和1602LCM等组成的温度测量显示装置,为了进行比较,现将单片机换成ARM而其它部分不变,即用DS18B20测量温度,通过1602LCM显示温度值,其原理图如下所示。另外本人使用的是Easy ARM1138开发板,这样安装调试都很方便。



 d1c00362-b670-42ef-b243-6e19535719de.jpg


⒉        软件设计


本设计要求用DS18B20测量温度,通过1602LCM显示温度值,其流程图如下所示。需要注意的是,在启动温度转换后需要等待750毫秒以上,本例是采用延时的方式等待转换结束,如果在此期间CPU还要做其它事,则可以采用定时中断的方式来等待转换结束。


742c0924-2650-4279-a062-5aeaa04560be.jpg



该设计详细C语言程序如下,可以把51单片机的程序与之相比较,使自己更快的熟悉ARM单片计。


 


/***************************************************


基于ARM单片机  DS18B20+1602LCM


PF0-DQ(18B20),以下LCM:PA-数据,PF5-RS,PF6-RW,PF7-E


****************************************************/


#include  "systemInit.h"


#include  <hw_types.h>


#include  <hw_memmap.h>


#include  <hw_sysctl.h>


#include  <hw_gpio.h>


#include  <sysctl.h>


#include  <gpio.h>


 


//定义18B20


#define  DQ                    GPIO_PORTF_BASE , GPIO_PIN_0


 


//定义LCD


#define RS  GPIO_PORTF_BASE,GPIO_PIN_5


#define RW  GPIO_PORTF_BASE,GPIO_PIN_6


#define E   GPIO_PORTF_BASE,GPIO_PIN_7


#define AIO   GPIO_PORTA_BASE,0xff


 


#define uchar unsigned char


#define uint unsigned int


 


uchar display[5]={0,0,0,0,0};


uchar ditab[16]={0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9};    //温度的小数值


uchar tplsb,tpmsb;


 


//  延时1us


void  Delay(unsigned int  ulVal)


{


  unsigned int i,j;


  for(i=0;i<ulVal;i++)


    j++; 


}


 


//  延时1ms


void  Delay1(unsigned int  ulVal)


{


  unsigned int i,j;


  for(i=0;i<ulVal;i++)


  {


    for(j=0;j<1000;j++)


    Delay(1);


  }


}


 


//  定义全局的系统时钟变量


unsigned long TheSysClock = 12000000UL;


 


//  系统时钟初始化


void clockInit(void)


{


    SysCtlLDOSet(SYSCTL_LDO_2_50V);                   //  设置LDO输出电压


 


    SysCtlClockSet(SYSCTL_USE_OSC |                  //  系统时钟设置


                   SYSCTL_OSC_MAIN |                //  采用主振荡器


                   SYSCTL_XTAL_6MHZ |               //  外接6MHz晶振


                   SYSCTL_SYSDIV_1);                //  不分频


 


    TheSysClock = SysCtlClockGet();              //  获取当前的系统时钟频率


}


 


//LCD初始化


void LCD_Init(void)


{


  int i;


  GPIOPinWrite(AIO,0x30);  //GPIOA口出0x30


  GPIOPinWrite(RS,0) ;  //RS=0


  GPIOPinWrite(RW,0) ;  //RW=0


  for(i=0;i<3;i++)


  {


    GPIOPinWrite(E,0x01<<7) ;  //E=1


    GPIOPinWrite(E,0) ;  //E=0


    Delay(500* (TheSysClock / 4000000));      //  延时约500us     


  }


}


 


//LCD命令写


void Write_Com(uchar a)


{


  Delay(1000* (TheSysClock / 4000000));      //  延时约1ms


  GPIOPinWrite(RW,0);  //RW=0


  GPIOPinWrite(RS,0) ;  //RS=0


  GPIOPinTypeOut(AIO);    //GPIO A为输出


  GPIOPinWrite(AIO,a);  //GPIO A口出a


  GPIOPinWrite(E,0x01<<7) ;  //E=1


  GPIOPinWrite(E,0) ;  //E=0


}


 


//LCD数据写


void Write_Data(uchar a)


{


  Delay(1000* (TheSysClock / 4000000));      //  延时约1ms


  GPIOPinWrite(RW,0) ;  //RW=0


  GPIOPinTypeOut(AIO);    //GPIOA为输出


  GPIOPinWrite(RS,0x01<<5) ;  //RS=1


  GPIOPinWrite(AIO,a);  //GPIO A口出a


  GPIOPinWrite(E,0x01<<7) ;  //E=1


  GPIOPinWrite(E,0) ;  //E=0


}


 


/* 产生复位脉冲初始化DS18B20 */


void TxReset(void)


{


  uint i;


  HWREGB(0x40025400)|=1;          //设置DQ为输出


  GPIOPinWrite(DQ, 0);          /* 拉低约900us */


  i= 1000;


  while (i>0)   i--;   


  GPIOPinWrite(DQ, 1);              // 产生上升沿


  i = 36;


  while (i>0)   i--;


}


 


/* 等待应答脉冲 */


void RxWait(void)


{


  uint i,data;


  HWREGB(0x40025400)&=0xfe;            //设置DQ为输入


  do


  {


    data=GPIOPinRead(DQ);


    data=(data)&1;


  }


  while(data);


  do


  {


    data=GPIOPinRead(DQ);


    data=(data)&1;


  }


  while(!data);        // 检测到应答脉冲


  i = 15;


  while (i>0)   i--;


}


 


/* 读取数据的一位,满足读时隙要求 */


uchar RdBit(void)


{


  uint i,b;


  HWREGB(0x40025400)|=1;     //设置DQ为输出


  GPIOPinWrite(DQ, 0);


  i =1;


  while (i>0)   i--;


  HWREGB(0x40025400)&=0xfe;          //设置DQ为输入


  GPIOPinWrite(DQ, 1);


  i = 15;


  while (i>0)   i--;


  b = GPIOPinRead(DQ);


  b=(b)&1;


  i = 110;


  while(i>0) i--;


  return (b);


}


 


/* 读取数据的一个字节 */


uchar RdByte(void)


{


  uchar i,j,b;


  b = 0;


  for (i=1;i<=8;i++)


  {


    j = RdBit();


    b = (j<<7)|(b>>1);


  }


  return(b);


}


 


/* 写数据的一个字节,满足写1和写0的时隙要求 */


void WrByte(uchar b)


{


  uint i;


  uchar j,btmp;


  HWREGB(0x40025400)=1;       //设置DQ为输出


  for(j=1;j<=8;j++)


  {


    btmp = b&1;


    b = b>>1;       // 取下一位(由低位向高位)


    if (btmp)


    {       /* 写1 */


      GPIOPinWrite(DQ, 0);


      i = 15;


      while(i>0) i--;   // 延时,使得15us以内拉高


      GPIOPinWrite(DQ, 1);


      i = 100;


      while(i>0) i--;   // 整个写1时隙不低于60us


    }


    else


    {       /* 写0 */


      GPIOPinWrite(DQ, 0);         


      i = 110;


      while(i>0) i--;   // 保持低在60us到120us之间


      GPIOPinWrite(DQ, 1);


      i = 15;


      while(i>0) i--;


     }


  }


}


 


/* 启动温度转换 */


void convert(void)


{


  TxReset();            // 产生复位脉冲,初始化DS18B20


  RxWait();         // 等待DS18B20给出应答脉冲


  Delay1(1);            // 延时


  WrByte(0xcc);     //跳过rom命令


  WrByte(0x44);     //启动温度转换命令


}


 


/* 读取转换结果 */


void RdTemp(void)


{


  TxReset();            // 产生复位脉冲,初始化DS18B20


  RxWait();         // 等待DS18B20给出应答脉冲


  Delay1(1);            // 延时


  WrByte(0xcc);     //跳过rom命令


  WrByte(0xbe);     //读取暂存器命令


  tplsb = RdByte(); // 温度值低位字节(其中低4位为二进制的“小数”部分)


  tpmsb = RdByte(); // 高位值高位字节(其中高5位为符号位)    


}


 


//温度数据处理函数


void work_temp(void)


{


  unsigned char n=0;


  if(tpmsb>127)


  {


    tpmsb=(256-tpmsb);        //负温度求补码


    tplsb=(256-tplsb);


    n=1;


  }


  display[4]=tplsb&0x0f;


  display[0]=ditab[display[4]];                     //温度的小数


  display[4]=((tplsb&0xf0)>>4)|((tpmsb&0x0f)<<4);


  display[3]=display[4]/100;                        //温度的百位


  display[1]=display[4]%100;


  display[2]=display[1]/10;                         //温度的十位


  display[1]=display[1]%10;                         //温度的个位


  if(n)


  Delay(1);             //延时10us


}  


 


//  主函数(程序入口)


int main(void)


{


  clockInit();                               //  时钟初始化:晶振,6MHz


  SysCtlPeriEnable(SYSCTL_PERIPH_GPIOA);    //使能GPIOA口外设


  GPIOPinTypeOut(GPIO_PORTA_BASE ,0xFF);    //GPIOA为输出


  SysCtlPeriEnable(SYSCTL_PERIPH_GPIOF);    //使能18B20DAT所在的GPIO端口


  SysCtlPeriEnable(SYSCTL_PERIPH_GPIOF);    //使能GPIOF口外设


  GPIOPinTypeOut(GPIO_PORTF_BASE ,0xFF);    //GPIOF为输出


         


  LCD_Init();                          //LCD初始化


  Write_Com(0x38);                    //设置工作方式


  Write_Com(0x01);                    //清除显示


  Write_Com(0x06);                    //设置输入方式


  Write_Com(0x0c);                    //设置显示方式


  Write_Com(0x80);                    //DDRAM第一行的首地址


  Write_Data(0x54);                  //显示Test by DS18B20


  Write_Data(0x65);


  Write_Data(0x73);


  Write_Data(0x74);


  Write_Data(0x20);


  Write_Data(0x62);


  Write_Data(0x79);


  Write_Data(0x20);


  Write_Data(0x44);             


  Write_Data(0x53);


  Write_Data(0x31);


  Write_Data(0x38);


  Write_Data(0x42);


  Write_Data(0x32);


  Write_Data(0x30);


  for (;;)


  {


    convert();               //启动温度转换


    Delay1(800);             //延时800ms


    RdTemp();              //读取转换结果


    work_temp();           //温度数据处理


    GPIOPinTypeOut(GPIO_PORTF_BASE ,0xFF);    //GPIO F为输出


    Write_Com(0xc0);                    //DDRAM第二行的首地址


    Write_Data(0x54);                   //显示Temp:


    Write_Data(0x65);


    Write_Data(0x6d);


    Write_Data(0x70);


    Write_Data(0x3a);


    if(display[3]==0)                   //显示温度值


          Write_Data(0x20);


    else


        Write_Data(0x30+display[3]);


    Write_Data(0x30+display[2]);


    Write_Data(0x30+display[1]);


    Write_Data(0x2e);


    Write_Data(0x30+display[0]);


    Write_Data(0xdf);


    Write_Data(0x43);


  }


}


 


本人使用的是IAR EWARM(IAR Embedded Workbench for ARM)集成开发环境,利用周立功公司提供的工程模板,输入以上的源程序,点击菜单“Project”→“Mark”进行编译,或按F7键,根据提示修改错误,再进行编译直至无错误为止 。


 


3  软件调试


编译无误后即可点击菜单“Project”→“Dbuge”下载源程序的机器码至开发板(或按Ctrl+D),同时在桌面上出现了几个调试用的快捷按钮——运行(go)、运行到光标处(Run to Cursor)、步出(Step Out)、步入(Step Into)、步越(Step Over)、停止(Break)、复位(Reset)等。通过选择上述不同的快捷按钮,以及观察变量的值(点击菜单“View”→“Watch”在Expression中输入变量名,即可在Value中看到该变量的值;或将光标悬停在某变量上,即可看到该变量的值),来调试程序,直至一切无误后即可全速运行了(点击快捷按钮go)。实物照片如下所示。



 d11e5ec8-12d2-45a4-8d96-31c94e9c49fa.JPG

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
14
关闭 站长推荐上一条 /3 下一条