- UID
- 523946
- 性别
- 男
|
基于ARM单片机的单总线应用 单总线(1-Wire)是美国达拉斯半导体公司的一项专利技术。与目前广泛应用的其他串行数据通信方式不同,它采用单根信号线完成数据的双向传输,具有节省I/O引脚资源、结构简单、成本低廉、便于总线扩展等诸多优点。关于单总线技术及其芯片的介绍,请参考有关资料。
⒈ 硬件设计
在我的博文“基于51单片机的单总线”中介绍了采用51单片机、DS18B20和1602LCM等组成的温度测量显示装置,为了进行比较,现将单片机换成ARM而其它部分不变,即用DS18B20测量温度,通过1602LCM显示温度值,其原理图如下所示。另外本人使用的是Easy ARM1138开发板,这样安装调试都很方便。
⒉ 软件设计
本设计要求用DS18B20测量温度,通过1602LCM显示温度值,其流程图如下所示。需要注意的是,在启动温度转换后需要等待750毫秒以上,本例是采用延时的方式等待转换结束,如果在此期间CPU还要做其它事,则可以采用定时中断的方式来等待转换结束。
该设计详细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)。实物照片如下所示。 |
|