MSP430的软硬件C延时程序设计
- 格式:doc
- 大小:124.50 KB
- 文档页数:8
【精确延时函数】IAR(MSP430)中的精确延时函数在IAR 软件430 的编译器里面我们可以利用它内部的延时子程序来实现我们想要的高精度软件延时,方法如下:具体如下【引用别人的,这个延时函数很高】:注意:__delay_cycles(x),x 必须是常量或则是常量表达式,如果是变量则编译报错!IAR FOR AVR 中精确软件延时方法在用单片机的时候常常会用到延时函数,430 也不例外,常见的形式有:void delay(unsigned int ms){unsigned int i,j;for( i=0;idelay_ms(1000);//延时1 秒-------------------------------------------------------------------------------------原因:__delay_cycles()是编译系统”涵数”,IAR编译时会替换成相应的循环代码.看图片,要求delay 100 指令(时钟)周期,编译后刚好100 周期.使用这种延时需要注意:ourdev/thread-756021-1-1.html#define _delay_us(A)__delay_cycles( (uint32) ( (double)(F_CPU) *((A)/1000000.0) + 0.5))#define _delay_ms(A)__delay_cycles( (uint32) ( (double)(F_CPU)*((A)/1000.0) + 0.5))#define _delay_s(A)__delay_cycles( (uint32) ( (double)(F_CPU)*((A)/1.0) + 0.5))tips:感谢大家的阅读,本文由我司收集整编。
仅供参阅!。
>>>>>>>>>>>BoardConfig.h<<<<<<<<<<<typedef unsigned char uchar;typedef unsigned int uint;//控制位的宏定义#define Ctrl_Out P3DIR |= BIT3 + BIT6 + BIT7;#define Ctrl_0 P3OUT &= ~(BIT3 + BIT6 + BIT7)#define SRCLK_1 P3OUT |= BIT7#define SRCLK_0 P3OUT &= ~BIT7#define SER_1 P3OUT |= BIT6#define SER_0 P3OUT &= ~BIT6#define RCLK_1 P3OUT |= BIT3#define RCLK_0 P3OUT &= ~BIT3//板上资源配置函数void BoardConfig(uchar cmd){uchar i;Ctrl_Out;Ctrl_0;for(i = 0; i < 8; i++){SRCLK_0;if(cmd & 0x80) SER_1;else SER_0;SRCLK_1;cmd <<= 1;}RCLK_1;_NOP();RCLK_0;}>>>>>>>>>>>cry1602.h<<<<<<<<<<<void DispNChar(unsigned char x,unsigned char y, unsigned char n,unsigned char *ptr); void LocateXY(unsigned char x,unsigned char y);void Disp1Char(unsigned char x,unsigned char y,unsigned char data);void LcdReset(void);void LcdWriteCommand(unsigned char cmd,unsigned char chk);void LcdWriteData( unsigned char data );void WaitForEnable(void);void Delay5ms(void);void Delay400ms(void);>>>>>>>>>>>cry1602.c<<<<<<<<<<<#include <msp430x14x.h>#include "cry1602.h"typedef unsigned char uchar;typedef unsigned int uint;/**************宏定义***************/#define DataDir P4DIR#define DataPort P4OUT#define Busy 0x80#define CtrlDir P3DIR#define CLR_RS P3OUT&=~BIT0; //RS = P3.0 #define SET_RS P3OUT|=BIT0;#define CLR_RW P3OUT&=~BIT1; //RW = P3.1#define SET_RW P3OUT|=BIT1;#define CLR_EN P3OUT&=~BIT2; //EN = P3.2#define SET_EN P3OUT|=BIT2;/*******************************************函数名称:DispNchar功 能:让液晶从某个位置起连续显示N个字符参 数:x--位置的列坐标y--位置的行坐标n--字符个数ptr--指向字符存放位置的指针返回值 :无********************************************/void DispNChar(uchar x,uchar y, uchar n,uchar *ptr) {uchar i;for (i=0;i<n;i++){Disp1Char(x++,y,ptr[i]);if (x == 0x0f){x = 0;y ^= 1;}}}/*******************************************函数名称:LocateXY功 能:向液晶输入显示字符位置的坐标信息参 数:x--位置的列坐标y--位置的行坐标返回值 :无********************************************/void LocateXY(uchar x,uchar y){uchar temp;temp = x&0x0f;y &= 0x01;if(y) temp |= 0x40; //如果在第2行temp |= 0x80;LcdWriteCommand(temp,1);}/*******************************************函数名称:Disp1Char功 能:在某个位置显示一个字符参 数:x--位置的列坐标y--位置的行坐标data--显示的字符数据返回值 :无********************************************/void Disp1Char(uchar x,uchar y,uchar data){LocateXY( x, y );LcdWriteData( data );}/*******************************************函数名称:LcdReset功 能:对1602液晶模块进行复位操作参 数:无返回值 :无********************************************/void LcdReset(void){CtrlDir |= 0x07; //控制线端口设为输出状态 DataDir = 0xFF; //数据端口设为输出状态 LcdWriteCommand(0x38, 0); //规定的复位操作Delay5ms();LcdWriteCommand(0x38, 0);Delay5ms();LcdWriteCommand(0x38, 0);Delay5ms();LcdWriteCommand(0x38, 1); //显示模式设置LcdWriteCommand(0x08, 1); //显示关闭LcdWriteCommand(0x01, 1); //显示清屏LcdWriteCommand(0x06, 1); //写字符时整体不移动LcdWriteCommand(0x0c, 1); //显示开,不开游标,不闪烁}函数名称:LcdWriteCommand功 能:向液晶模块写入命令参 数:cmd--命令,chk--是否判忙的标志,1:判忙,0:不判返回值 :无********************************************/void LcdWriteCommand(uchar cmd,uchar chk){if (chk) WaitForEnable(); // 检测忙信号?CLR_RS;CLR_RW;_NOP();DataPort = cmd; //将命令字写入数据端口 _NOP();SET_EN; //产生使能脉冲信号_NOP();_NOP();CLR_EN;}/*******************************************函数名称:LcdWriteData功 能:向液晶显示的当前地址写入显示数据参 数:data--显示字符数据返回值 :无********************************************/void LcdWriteData( uchar data ){WaitForEnable(); //等待液晶不忙SET_RS;CLR_RW;_NOP();DataPort = data; //将显示数据写入数据端口_NOP();SET_EN; //产生使能脉冲信号_NOP();_NOP();CLR_EN;}/*******************************************函数名称:WaitForEnable功 能:等待1602液晶完成内部操作参 数:无返回值 :无void WaitForEnable(void){P4DIR &= 0x00; //将P4口切换为输入状态CLR_RS;SET_RW;_NOP();SET_EN;_NOP();_NOP();while((P4IN & Busy)!=0); //检测忙标志CLR_EN;P4DIR |= 0xFF; //将P4口切换为输出状态}/******************************************* 函数名称:Delay5ms功 能:延时约5ms参 数:无返回值 :无********************************************/ void Delay5ms(void){uint i=40000;while (i != 0){i--;}}/******************************************* 函数名称:Delay400ms功 能:延时约400ms参 数:无返回值 :无********************************************/ void Delay400ms(void){uchar i=50;uint j;while(i--){j=7269;while(j--);}}>>>>>>>>>>>IIC.h<<<<<<<<<<<void Set_IO(void);void delay(void);void start(void);void stop(void);void mack(void);void mnack(void);unsigned char check(void);void write1(void);void write0(void);void write1byte(unsigned char wdata);unsigned char writeNbyte(unsigned char * outbuffer,unsigned char n); unsigned char read1byte(void);void readNbyte(unsigned char * inbuffer,unsigned char n); >>>>>>>>>>>IIC.c<<<<<<<<<<<#include <msp430x14x.h>typedef unsigned char uchar;typedef unsigned int uint;#define SCL_H P1OUT |= BIT1#define SCL_L P1OUT &= ~BIT1#define SDA_H P1OUT |= BIT0#define SDA_L P1OUT &= ~BIT0#define SCL_out P1DIR |= BIT1 //SCL设置为输出模式#define SDA_in P1DIR &= ~BIT0 //SDA改成输入模式#define SDA_out P1DIR |= BIT0 //SDA变回输出模式#define SDA_val P1IN&BIT0 //SDA的位值#define TRUE 1#define FALSE 0/*******************************************函数名称:Set_IO功 能:设置IIC对应IO为输出方向并输出高电平参 数:无返回值 :无********************************************/void Set_IO(void){SCL_out;SDA_out;SCL_H;SDA_H;}/******************************************* 函数名称:delay功 能:延时约100us的时间参 数:无返回值 :无********************************************/ void delay(void){uchar i;for(i = 0;i < 15;i++)_NOP();}/******************************************* 函数名称:start功 能:完成IIC的起始条件操作参 数:无返回值 :无********************************************/ void start(void){SCL_H;SDA_H;delay();SDA_L;delay();SCL_L;delay();}/******************************************* 函数名称:stop功 能:完成IIC的终止条件操作参 数:无返回值 :无********************************************/ void stop(void){SCL_H;SDA_L;delay();SDA_H;delay();}/*******************************************函数名称:check功 能:检查从机的应答操作参 数:无返回值 :从机是否有应答:1--有,0--无********************************************/ uchar check(void){uchar slaveack;SDA_in;SCL_H;delay();slaveack = SDA_val; //读入SDA数值SCL_L;delay();SDA_out;if(slaveack) return FALSE;else return TRUE;}/******************************************* 函数名称:write1功 能:向IIC总线发送一个1参 数:无返回值 :无********************************************/ void write1(void){SDA_H;delay();SCL_H;delay();SCL_L;delay();}/******************************************* 函数名称:write0功 能:向IIC总线发送一个0参 数:无返回值 :无********************************************/ void write0(void){SDA_L;delay();SCL_H;delay();SCL_L;delay();}/*******************************************函数名称:write1byte功 能:向IIC总线发送一个字节的数据参 数:wdata--发送的数据返回值 :无********************************************/void write1byte(uchar wdata){uchar i;for(i = 8;i > 0;i--){if(wdata & 0x80) write1();else write0();wdata <<= 1;}}>>>>>>>>>>>EEPROM.h<<<<<<<<<<<unsigned char Write_1Byte(unsigned char wdata,unsigned char dataaddress); unsigned char Write_NByte(unsigned char * outbuf,unsigned char n,unsigned char dataaddress);unsigned char Read_1Byte_currentaddress(void);unsigned char Read_NByte_currentaddress(unsigned char * readbuf,unsigned char n); unsigned char Read_1Byte_Randomaddress(unsigned char dataaddress);unsigned char Read_NByte_Randomaddress(unsigned char * readbuf,unsigned char n,unsigned char dataaddress);>>>>>>>>>>>EEPROM.c<<<<<<<<<<<#include "IIC.h"typedef unsigned char uchar;typedef unsigned int uint;#define deviceaddress 0xa0 //AT24C02的设备地址/*******************************************函数名称:delay_10ms功 能:延时约6ms,等待EEPROM完成内部写入参 数:无返回值 :无********************************************/void delay_10ms(void){uint i = 1000;while(i--);}/*******************************************函数名称:Write_1Byte功 能:向EEPROM中写入1个字节的数据参 数:Wdata--写入的数据dataaddress--数据的写入地址返回值 :写入结果:1--成功,0--失败********************************************/uchar Write_1Byte(uchar wdata,uchar dataaddress){start();write1byte(deviceaddress);if(check()) write1byte(dataaddress);else return 0;if(check()) write1byte(wdata);else return 0;if(check()) stop();else return 0;delay_10ms(); //等待EEPROM完成内部写入return 1;}/*******************************************函数名称:Write_NByte功 能:向EEPROM中写入N个字节的数据参 数:outbuf--指向写入数据存放首地址的指针n--数据个数,最大不能超过8,由页地址决定其最大长度dataaddress--数据写入的首地址返回值 :写入结果:1--成功,0--失败********************************************/uchar Write_NByte(uchar * outbuf,uchar n,uchar dataaddress){uchar flag;start();write1byte(deviceaddress); //写入器件地址if(check() == 1)write1byte(dataaddress); //写入数据字地址 elsereturn 0;if(check())flag=writeNbyte(outbuf,n);elsereturn 0;delay_10ms(); //等待EEPROM完成内部写入 if(flag) return 1;else return 0;}/*******************************************函数名称:Read_1Byte_currentaddress功 能:从EEPROM的当前地址读取1个字节的数据参 数:无返回值 :读取的数据********************************************/ uchar Read_1Byte_currentaddress(void){uchar temp;start();write1byte((deviceaddress|0x01));if(check())temp = read1byte();elsereturn 0;mnack();stop();return temp;}/*******************************************函数名称:Read_NByte_currentaddress功 能:从EEPROM的当前地址读取N个字节的数据参 数:readbuf--指向保存数据地址的指针n--读取数据的个数返回值 :读取结果:1--成功,0--失败********************************************/ uchar Read_NByte_currentaddress(uchar * readbuf,uchar n) {start();write1byte((deviceaddress|0x01));if(check())readNbyte(readbuf,n);elsereturn 0;return 1;}/*******************************************函数名称:Read_1Byte_Randomaddress功 能:从EEPROM的指定地址读取1个字节的数据参 数:dataaddress--数据读取的地址返回值 :读取的数据********************************************/uchar Read_1Byte_Randomaddress(uchar dataaddress){uchar temp;start();write1byte(deviceaddress);if(check())write1byte(dataaddress);elsereturn 0;if(check()){start();write1byte((deviceaddress|0x01));}elsereturn 0;if(check())temp = read1byte();elsereturn 0;mnack();stop();return temp;}/*******************************************函数名称:Read_NByte_Randomaddress功 能:从EEPROM的指定地址读取N个字节的数据参 数:readbuf--指向保存数据地址的指针n--读取数据的个数dataaddress--数据读取的首地址返回值 :读取结果:1--成功,0--失败********************************************/uchar Read_NByte_Randomaddress(uchar * readbuf,uchar n,uchar dataaddress) {start();write1byte(deviceaddress);if(check())write1byte(dataaddress);elsereturn 0;if(check()){start();write1byte(deviceaddress|0x01);}elsereturn 0;if(check())readNbyte(readbuf,n);elsereturn 0;return 1;}>>>>>>>>>>>ds1302.h<<<<<<<<<<< void delay(unsigned int time);void Reset_DS1302(void);void Write1Byte(unsigned char wdata);unsigned char Read1Byte(void);void W_Data(unsigned char addr, unsigned char wdata); unsigned char R_Data(unsigned char addr);void BurstWrite1302(unsigned char *ptr);void BurstRead1302(unsigned char *ptr);void BurstWriteRAM(unsigned char *ptr);void BurstReadRAM(unsigned char *ptr);void Set_DS1302(unsigned char *ptr);void Get_DS1302(unsigned char *ptr); >>>>>>>>>>>ds1302.c<<<<<<<<<<< #include <msp430x14x.h>typedef unsigned char uchar;typedef unsigned int uint;/**************宏定义***************/#define DS_RST BIT7 //DS_RST = P2.7#define DS_SCL BIT5 //DS_SCL = P2.5#define DS_SDA BIT6 //DS_SDA = P2.6#define DS_RST_IN P2DIR &= ~DS_RST#define DS_RST_OUT P2DIR |= DS_RST#define DS_RST0 P2OUT &= ~DS_RST#define DS_RST1 P2OUT |= DS_RST#define DS_SCL_IN P2DIR &= ~DS_SCL#define DS_SCL_OUT P2DIR |= DS_SCL#define DS_SCL0 P2OUT &= ~DS_SCL#define DS_SCL1 P2OUT |= DS_SCL#define DS_SDA_IN P2DIR &= ~DS_SDA#define DS_SDA_OUT P2DIR |= DS_SDA#define DS_SDA0 P2OUT &= ~DS_SDA#define DS_SDA1 P2OUT |= DS_SDA#define DS_SDA_BIT P2IN & DS_SDA/*******************************************函数名称:delay功 能:延时一段时间参 数:time--延时长度返回值 :无********************************************/ void delay(uint time){uint i;for(i=0;i<time;i++) _NOP();}/*******************************************函数名称:Reset_DS1302功 能:对DS1302进行复位操作参 数:无返回值 :无********************************************/ void Reset_DS1302(void){DS_RST_OUT; //RST对应的IO设置为输出状态DS_SCL_OUT; //SCLK对应的IO设置为输出状态 DS_SCL0; //SCLK=0DS_RST0; //RST=0delay(10);DS_SCL1; //SCLK=1}/*******************************************函数名称:Write1Byte功 能:对DS1302写入1个字节的数据参 数:wdata--写入的数据返回值 :无********************************************/ void Write1Byte(uchar wdata){uchar i;DS_SDA_OUT; //SDA对应的IO设置为输出状态 DS_RST1; //REST=1;for(i=8; i>0; i--){if(wdata&0x01) DS_SDA1;else DS_SDA0;DS_SCL0;delay(10);DS_SCL1;delay(10);wdata >>=1;}}/******************************************* 函数名称:Read1Byte功 能:从DS1302读出1个字节的数据参 数:无返回值 :读出的一个字节数据********************************************/ uchar Read1Byte(void){uchar i;uchar rdata=0X00;DS_SDA_IN; //SDA对应的IO设置为输入状态 DS_RST1; //REST=1;for(i=8; i>0; i--){DS_SCL1;delay(10);DS_SCL0;delay(10);rdata >>=1;if(DS_SDA_BIT) rdata |= 0x80;}return(rdata);}/******************************************* 函数名称:W_Data功 能:向某个寄存器写入一个字节数据参 数:addr--寄存器地址wdata--写入的数据返回值 :无********************************************/ void W_Data(uchar addr, uchar wdata){DS_RST0;DS_SCL0;_NOP();DS_RST1;Write1Byte(addr); //写入地址Write1Byte(wdata); //写入数据DS_SCL1;DS_RST0;}/*******************************************函数名称:R_Data功 能:从某个寄存器读出一个字节数据参 数:addr--寄存器地址返回值 :读出的数据********************************************/uchar R_Data(uchar addr){uchar rdata;DS_RST0;DS_SCL0;_NOP();DS_RST1;Write1Byte(addr); //写入地址rdata = Read1Byte(); //读出数据DS_SCL1;DS_RST0;return(rdata);}/*******************************************函数名称:BurstWrite1302功 能:以burst方式向DS1302写入批量时间数据参 数:ptr--指向时间数据存放地址的指针返回值 :读出的数据说 明:时间数据的存放格式是:秒,分,时,日,月,星期,年,控制 【7个数据(BCD格式)+1个控制】********************************************/void BurstWrite1302(uchar *ptr){uchar i;W_Data(0x8e,0x00); //允许写入DS_RST0;DS_SCL0;_NOP();DS_RST1;Write1Byte(0xbe); // 0xbe:时钟多字节写入命令for (i=8; i>0; i--){Write1Byte(*ptr++);}DS_SCL1;DS_RST0;W_Data(0x8e,0x80); // 禁止写入}/*******************************************函数名称:BurstRead1302功 能:以burst方式从DS1302读出批量时间数据参 数:ptr--指向存放时间数据地址的指针返回值 :无说 明:时间数据的存放格式是:秒,分,时,日,月,星期,年,控制 【7个数据(BCD格式)+1个控制】********************************************/void BurstRead1302(uchar *ptr){uchar i;DS_RST0;DS_SCL0;_NOP();DS_RST1;Write1Byte(0xbf); //0xbf:时钟多字节读命令for (i=8; i>0; i--){*ptr++ = Read1Byte();}DS_SCL1;DS_RST0;}/*******************************************函数名称:BurstWriteRAM功 能:以burst方式向DS1302的RAM中写入批量数据参 数:ptr--指向存放数据地址的指针返回值 :无说明 :共写入31个字节的数据********************************************/void BurstWriteRAM(uchar *ptr){uchar i;W_Data(0x8e,0x00); //允许写入DS_RST0;DS_SCL0;_NOP();DS_RST1;Write1Byte(0xfe); //0xfe:RAM多字节写命令for (i = 31; i>0; i--) //RAM共有31个字节{Write1Byte(*ptr++);}DS_SCL1;DS_RST0;W_Data(0x8e,0x80); //禁止写入}/*******************************************函数名称:BurstReadRAM功 能:以burst方式从DS1302的RAM中读出批量数据参 数:ptr--指向数据存放地址的指针返回值 :无说明 :共读出31个字节的数据********************************************/void BurstReadRAM(uchar *ptr){uchar i;DS_RST0;DS_SCL0;_NOP();DS_RST1;Write1Byte(0xff); //0xff:RAM的多字节读命令for (i=31; i>0; i--){*ptr++ = Read1Byte();}DS_SCL1;DS_RST0;}/*******************************************函数名称:Set_DS1302功 能:设置DS1302内部的时间参 数:ptr--指向存放数据地址的指针返回值 :无说明 :写入数据的格式:秒 分 时 日 月 星期 年 【共7个字节】 ********************************************/void Set_DS1302(uchar *ptr){uchar i;uchar addr = 0x80;W_Data(0x8e,0x00); //允许写入for(i =7;i>0;i--){W_Data(addr,*ptr++);addr += 2;}W_Data(0x8e,0x80); //禁止}/*********************************************************** 名称: Get_DS1302* 说明:* 功能: 读取DS1302当前时间* 调用: R_Data(uchar addr)* 输入: ucCurtime: 保存当前时间地址。
MSP430系列C语言环境下的软件设计实用技巧李文炜(杭州师范学院信息工程学院,浙江杭州310036) 摘要: 介绍MSP430系列Flash型单片机内部的Flash控制器的结构,以MSP430F149为例介绍如何在C编译环境下对Flash存储器进行在线擦除和编程操作,并且就实际现场的基于裸机的首次参数保存提出了实用建议,给出了数组结构参数保存的实际C语言例程。
关键词: MSP430;Flash;C编译;擦除程序;设计技巧 中图分类号:TP311 文献标识码:B 文章编号:100023932(2004)(06)200362031 引 言[1~2]MSP430系列Flash型单片机内部集成有Flash 控制器,可以采用外部编程器进行烧写,也可以利用自己的程序修改Flash的内容,且不用外加编程电压。
Flash的可自编程性表示:用Flash存储器中的驻留软件或程序对Flash存储器进行擦除/编程,但是要求运行程序代码的存储区与待编程的存储区不在同一模块中。
由于MSP430系列单片机只有一个片上Flash存储器模块的微处理器,因此不能同时进行擦除/编程Flash的操作。
目前,在擦除/编程Flash 的过程中,通常将CPU置于空闲状态。
因此在进行系统设计时,可以利用片内的Flash保存一些运行数据,实现掉电保护;还可以修改Flash中的整个程序或局部程序,实现系统升级。
本文详细举例介绍了在嵌入式系统设计应用过程中积累的MSP430系列C语言环境下的软件设计实用技巧。
2 基于裸机的微处理器软件设计思想以微处理器为核心的系统开发,其系统的实时性,可靠性和使用的人性化与设计人员的水平和经验密切相关。
如图1所示,基于裸机的编程核心实际上就是应用系统在上电以后不断地做一个循环,在有外部响应的的条件下根据响应级别的高低,完成相应的功能操作。
3 微处理器在C语言环境下的软件设计技巧3.1 基于裸机的首次上电操作由图1可以看出,基于裸机开发出来的产品在第一次出厂时MSP430F149微处理器内部的Flash存储空间是一堆乱码,那么如果直接进入循环程序,利用内部随机参数计算出来的数据是无效的。
MSP4301.时钟控制:430三个时钟源:LFXT1CLK低频时钟源,XT2CLK,高频时钟源,DCOCLK数控RC 振荡器。
2.三种时钟源可提供三种时钟信号:1.ACLK辅助时钟:ACLK是LFXT1CLK信号经过1、2、4、8分频得到的。
ACLK可由软件选作外围器件的时钟信号。
2.MCLK系统主时钟:可由软件来设置来源于低频时钟源,高频,数控。
之后可再经过1、2、4、8分频得到。
MCLK主要用于CPU和系统。
3.SMCLK:可有软件选这高频时钟来源,用于高速外围设备。
其中P1.4/SMCLK, P2.0/ACLK, P5.5/SMCLK, P5.6/ACLK。
时钟信号输出,可由PnSEL|=0xXX,l来设置特殊功能端口。
4.三个振荡器的控制位:1.低频LFXT1:OscOff;2.高频XT2CLK:XT2OFF;3.DCO:SCG0;5.一、时钟模块主要由三个寄存器来进行控制。
1.DCOCTL DCO控制器高三位:DCO.2、DCO.1 DCO.0定义8种频率之一,相邻两位相差10%,第五位详细调整频率。
其中DCO为7时表示选择最高频率。
2.BCSCTL1基本时钟控制器1位数7(最高)---XT2OFF:控制XT2的开启与关闭,0:开启;1:关闭。
6---------XTS:控制LFXT1工作模式:0:低频工作模式32768HZ;1:高频工作模式(前提接了相应的高频晶振)。
5,4--------DIV.1、DIV.0:控制ACLK分频(ACLK时钟来源于LFXT1)0:不分;1: 2分;2: 4分;3:8分;3-------XT5V:此位设置为0;2,1,0-----Rsel.0~Rsel.2 :0~7:最低标频~最高标频。
3.BCSCTL27,6-------SELM.1,SELM.0:选择MCLK时钟源(系统主时钟)0,1:DCOCLK为时钟源2:XT2CLK为时钟源3:时钟源为LFXT1CLK5,4-------DIVM.0,DIVM.1 选择MCLK分频。
一、实验目的1.巩固编写和调试C语言程序的方法;2.了解简单电路的控制方法二、实验任务1.简单电子表的设计用8 个发光二极管以秒为单位显示时间值,按下面步骤完成一个简单电子表的设计:1)硬件连线:用跳线将L6~L1 分别与P2.5~P2.0 连接,L6~L1 用于显示秒值;用双口杜邦线将L7 与P5.0 连接,L8 与P5.1 连接,L8~L7 用于显示分钟值;蜂鸣器的控制端Buzz 与P4.1 连接;2)编写完整程序:计数秒值,用8 个发光二极管以二进制将时间显示出来,如图3-1,其中高两位显示分钟值(L8、L7),低6 位显示秒值(L6~L1),每60 秒,分钟值加1,黑色表示灯亮,则显示的时间表示表示3 分27 秒。
每计数到4 分钟时,控制蜂鸣器发出一报警声,然后又从0 开始重新计数。
其中1 秒时间可通过执行for(i=0;i<0x3FFFF;i++); 语句所花时间来调整。
实验的硬件图如下所示经过编写和调试程序,下面的程序可以满足试验的要求。
#include "io430.h"int main( void ){// Stop watchdog timer to prevent time out resetWDTCTL = WDTPW + WDTHOLD;P2SEL=0;P1SEL=0;P2DIR=0xFF;P1DIR=0xFF;unsignedinti,j,k,m;for(k=0;k<4;){for(j=0;j<60;j++){P2OUT=j;for(i=0;i<0xFFFF;i++);}k++;P1OUT=k;for(m=0;m<0x3FFFF;m++);}}3)(选做)增加按键控制功能:当按下KEY2 键时清零;按下KEY3 键时开始(或称继续)计时;按下KEY4 键时暂停计时。
硬件图如下图所示:程序如下所示#include "io430.h"void delay(unsigned inti) //定义一个1秒钟延时函数{unsignedint j;while(i--){for(j=0;j<125;j++);}}int main( void ){// Stop watchdog timer to prevent time out resetWDTCTL = WDTPW + WDTHOLD;P1SEL=0x00;P1DIR=0X00;P2SEL=0X00;P2DIR=0XFF;P4SEL_bit.P1=0;P4DIR_bit.P1=1;P5SEL=0x00;P5DIR=0xff;unsignedintl,m;while(1){P4OUT_bit.P1=1;P5OUT=0xff;P2OUT=0xff;if(P1IN_bit.P3==0){while(1){m=0;loop1:while(m<=3){for(l=0;l<60;l++){P2OUT=~l;if(P1IN_bit.P4==0){P2OUT=~l;P5OUT=~m;while((P1IN_bit.P3)&1==1);}if(P1IN_bit.P2==0){P2OUT=0xff;P5OUT=0xff;while((P1IN_bit.P3)&1==1){;} goto loop1;;}delay(100);}m++;P5OUT=~m;if((P5OUT&0x03)==0x03){ P4OUT_bit.P1=0;delay(10);P4OUT_bit.P1=1;P2OUT=0xff;}}}}}}思考题:1)如果硬件连线是将发光二极管LED8~LED1 分别与P2.7~P2.0 连接,按键Key4~Key2 分别与P1.4~P1.2 连接,蜂鸣器BUZZ 与P6.5 连接的话,实验板上连线,如何编程实现任务1?答:和选做部分几乎一样,只要改一下端口的连接,不在赘述了。
以MSP430F149为核心的温度检测仪的硬件模块和软件设计吕芮栋;张志文【摘要】温度检测仪主要是对温度进行检测,对温度的灵敏作出及时的反应.以MSP430F149为核心的温度检测仪成本较低,功耗低,有很高的可靠性,对周围环境抗干扰的能力也较强,对温度的变化反应灵敏,这就得益于其内部的硬件模块和软件设计,能够应用于不同的环境,据不同的需要应用在多类的温度检测系统中.这里从其硬件模块和软件设计对其特点进行分析、论证.%The temperature measuring instrument is mainly to detect temperature and respond to temperature change. The temperature measuring instrument based on MSP430F149 with low cost, low power consumption and high reliability, which has strong anti-interference ability for the surrounding environment, and is temperature sensitive. The hardware module and software design of the temperature measuring instrument can be applied to different environment. The features are analyzed and discussed from the hardware module and software design.【期刊名称】《现代电子技术》【年(卷),期】2012(035)001【总页数】3页(P199-201)【关键词】MSP430F149;检测系统;硬件;软件;低功耗【作者】吕芮栋;张志文【作者单位】西安工业大学电子信息工程学院,陕西西安710032;西安工业大学电子信息工程学院,陕西西安710032【正文语种】中文【中图分类】TN710-340 引言兰州大型的综合工程重离子加速器——冷却存储环(HIFRL-CSR)是国家科学重点工程之一,在其内部控制系统里存在着大量的测量温度的场合,这些场合依靠约束离子的行为发挥CSR主环中的磁场作用,在磁场中,这些带电粒子束有时处于聚焦状态,有时则处于传输状态,且磁场性能的好坏对束流品质有直接影响。
对MSP430单片机__delay_cycles精确延时的说明及改正在这里, 我来讨论一下关于MSP430单片机使用__delay_cycles延时的问题.IAR for MSP430编译器提供了一个编译器内联的精确延时函数(并非真正的函数)以提供用户精确延时使用, 该函数原型是:__intrinsic void __delay_cycles(unsigned long __cycles);该内部函数实现__cycles个CPU周期的延时,但对于该参数的设置,我要陈述一下:__cycles需要我们传递的是CPU运行的周期个数网上普遍的用法是:#define CPU_CLOCK 8000000#define delay_us(us)__delay_cycles(CPU_CLOCK/1000000*(us))#define delay_ms(ms) __delay_cycles(CPU_CLOCK/1000*(ms))在CPU主时钟频率为8MHz时, 这确实没有问题, 但是这样的写法: #define CPU_CLOCK 8000000这很容易让人们想到, 可以通过修改它的值以实现对不同主频系统参数的统一,其实这是不正确的! 比如修改为#define CPU_CLOCK 32768以实现32KHz主频的延时...下面来计算看看:当系统主时钟频率CPU_CLOCK为8MHz时:频率 f = 8MHz = 8,000,000Hz机器周期 Tm = 1/f = 1/8MHz = 1/8us也就是说,一个机器周期(nop)的时长是1/8us,所以延时1us即8*Tm,同上面:#define delay_us(us) __delay_cycles(8*(us))#define delay_ms(ms) __delay_cycles(8000*(ms))按照上面的宏定义方法,我们把CPU_CLOCK定义成32768,那么:频率 f = 32KHz = 32,768Hz机器周期 Tm = 1/f = 1/32768Hz ~= 30.5us可想而知,CPU最短的指令执行周期为30.5us, 这时, 想延时1us, 这可能吗?所以, 简单地把上面的定义改成#define CPU_CLOCK 32768是绝对错误的.同样, 还有些朋友实现了0.5us的延时, 这在当f = 1MHz = 1000000Hz时也是不现实的, 此时机器周期Tm = 1us. 在f = 8Mhz时, 4个机器周期为0.5us 尚可.所以, 为避免引起错误的使用或不正确的理解,最好像下面这样定义宏: #if CPU_CLOCK == 8000000#define delay_us(us) __delay_cycles(8*(us))#define delay_ms(ms) __delay_cycles(8000*(ms)) #else#pragma error "CPU_CLOCK is defined implicitly!"#endif另外:__delay_cycles 并不是真正的函数, 只是提供编译器内联展开,该函数并不支持变量参数, 其参数只能是常数.。
MSP430是超低功耗16位单片机,越来越受到电子工程师亲睐并得到广泛应用。
C程序直观,可读性好,易于移植和维护,已被很多单片机编程人员所采用。
MSP430集成开发环境(如IAR Embedded Workbench和AQ430)都集成了C编译器和C语言级调试器C—SPY。
但是C语言难以实现精确延时,这一直困扰着很多MSP430单片机程序员。
笔者在实际项目开发过程中,遇到很多需要严格时序控制的接口器件,如单总线数字温度传感器DSl8820、实时时钟芯片PCF8563(需要用普通]/o模拟12C总线时序)、三线制数字电位器AD8402、CF卡(Compact Flash Card)等都需要μs级甚至纳ns级精确延时;而一些慢速设备只需要ms到s级的延时。
为此,笔者提出了适合于不同延时级别需要的软件或硬件精确延时方法,并已实际应用,效果良好,大大缩短了开发周期。
1 硬件延时MSP430单片机系统程序多采用事件驱动机制,即在没有外部事件触发的情况下CPU休眠于低功耗模式中。
当外部事件到来时,产生中断激活CPU,进入相应的中断服务程序(ISR)中。
中断响应程序只完成两个任务,一是置位相应事件的标志,二是使MCU退出低功耗模式。
主程序负责使MCU在低功耗模式和事件处理程序之间切换,即在主程序中设一个无限循环,系统初始化以后直接进入低功耗模式。
MCU被唤醒后,判断各标志是否置位。
如果是单一标志置位,那么MCU执行相应的事件处理程序,完成后转入低功耗模式;若是有多个标志同时置位,主程序按照事先排好的消息队列对它们依次判别并进行处理,所有事件处理完毕以后MCU休眠,系统进入低功耗状态(该消息队列的顺序是按照任务的重要性设定的优先级)。
在这种前后台系统中,由于主程序是无限循环,就必须关闭看门狗,与其闲置,不如用其定时器的功能作硬件延时。
使用MSP430单片机看门狗定时器实现任意时长精确延时,既满足了系统实时低功耗的要求,也弥补了使用无限循环延时的时间难确定和占用CPU时间长的缺点。
通过下例,讲解在同一WDT ISR中完成不同时长延时的技巧。
#pragma vector=WD_r_VECTORinterrupt void WDT_Delay(void){//看门狗中断服务程序if((DelayTime&Delay500ms)==Delay500ms){//判断需要500 ms延时的标志是否置位static unsigned int n250MS=O;n250MS++;if(n250MS==2){ //延时250ms×2=500msn250MS=0;//清零计数器DelayTime&=~Delay500ms;//复位标志位WDTCTL=WDTHOLD+WDTPW;1El&=~WDTlE;//关闭看门狗定时器并禁止其中断}}if((DelayTime&Delay30s)==Delay30s){//判断需要的30 s延时标志是否置位static unsigned int nS=0;nS++;if(nS==30){ //延时1 s×30=30 snS=0;//清零计数器DelayTime&=~Delay30s;//复位标志位WDTCTL=WDTHOLD+WDTPW;IEl&=~WDTlE;//关闭看门狗定时器并禁止其中断}}}如果任务1需要500 ms的延时,只需在需要延时处执行如下语句:WDTCTL=WDT_ADLY_250;IE┃ =WDTIE;//①DelayTime┃=Delay500ms //②while((DelayTime&Delay500ms)==Delay500ms);//③①处是配置看门狗工作在定时器模式,WDT每隔250 ms产生一次中断请求。
可以根据需要改变时钟节拍,在使用32768 Hz晶振作为时钟源时,可以产生1.9ms、16 ms、250 ms和1000 ms的延时基数。
在头文件msp430xl4x.h中,将这4种翻转时间的WDT配置宏定义为:WDT_ADLY_1_9、WDT_ADLY_16、WDT_ADLY_250和WDT_ADLY_1000。
如果用DCOCLK 作为SMCLK的时钟源,WDT选择SMCLK=1 MHz为时钟源,这样可以有O.064 ms、0.5 ms、8 ms和32 ms延时基数可供使用。
②处设置一个标志位,方便WDT ISR判别并进入相应的延时分支。
③处一直判别DelayTime标志组中的Delay500ms位,如果处于置位状态,说明所需的延时未到,执行空操作,直到延时时间到,在WDTISR 中将Delay500ms复位,跳出while()循环,执行下一条指令。
同理,如果任务2需要30 s延时,通过WDTCTL=WDT_ADLY_1000激活WDT中断,每隔1 s进中断一次,在WDT ISR中判别标志发现是Delay30s 置位而不是Delay500ms执行30 s延时程序分支。
每中断一次,计数器nS加l,直到计到30,说明30 s延时完成,清零计数器,停止看门狗(WETCTL=WE)THOLD+WDTPW;)可停止产生中断,并复位该延时标志,以通知任务延时时间到,可以执行下面的指令了。
在WDT ISR中可以根据延时基数和计数器的搭配实现任意长度的时间延时。
在系统程序设计时,先确定所需的不同延时时间,然后在WDT。
ISR 中添加相应的延时分支即可。
嵌入式实时操作系统μC/OS—II移植于MSP430单片机就是使用看门狗定时器产生时钟节拍的。
对于系统比较简单,只需要单一时长的延时.而又要考虑系统功耗时,介绍另一种使用看门狗定时器中断完成延时的方法。
若要延时1 s,则设定WDT 每250 ms中断一次。
在需要延时处,启动看门狗定时器并允许其中断,系统进入低功耗模式3(共有5种.模式)休眠。
在中断服务程序中对延时时间累加,当达到1 s时唤醒CPU,并停止看门狗定时器中断。
实例代码如下:vold main(vold){WDTCTL=WDT_ADT_ADLY_250)//启动WDT,每250 ms中断一次IEI I=WDTIE)//使能看门狗定时器中断_BIS_SR(LPM3_bitS+GIE);//系统休眠于低功耗模式3,开总中断}#pragrna vector=WDT_VECTOR—interrupt void WDT_Delay(void){ //看门狗中断服务程序statlc unsigned charn=4;if(一一n==O){ //延时4×250 ms=1 s—BlC_SR_IRQ(LPM3_blts);//将CPU从低功耗模式3唤醒WDTCTL=WDTHOLD+WDTPW:IEl&=~WDTIE;)//关闭看门狗定时器并禁止其中断}这种方法充分发挥了MSP430系列的超低功耗特性,在等待延时的过程中,CPU不需要一直判断标志位以得知延时结束,而是进入省电模式。
等待过程中,只有极短的时间会在中断服务程序中累计时间并进行判断。
可以根据需要设置CPU进入不同的低功耗模式LPMx。
如果系统使用了多种外设中断,并在其他中断服务程序中也有唤醒CPU的语句,这种方法便不再适用了。
μs级延时不宜使用硬件延时,因为频繁的进出中断会使CPU用大量时间来响应中断和执行中断返回等操作。
硬件延时的方法适用于ms级以上的长时间延时。
2 软件延时在对数字温度传感器DS18820的操作中,用到的延时有:15μs、90μs、270 μs、540 μs等。
这些延时短暂,占用CPU时间不是太多,所以比较适合软件延时的方法。
通过汇编语言编写的程序,很容易控制时间,我们知道每条语句的执行时间,每段宏的执行时间及每段子程序加调用的语句所消耗的时间。
因此,要用C语言编制出较为精确的延时程序,就必须研究该段C 程序生成的汇编代码。
循环结构延时:延时时间等于指令执行时间与指令循环次数的乘积,举例来讲,对如下延时程序进行实验分析。
void delay(unsigned int time){while(time一一){};在main()中调用延时函数delayr(n);得到的延时时间是多少,需要在MSP430单片机的集成编译环境IAR Em—bedded Wclrkbeneh IDE 3.10A 中编制测试。
使用C430写好一段可执行代码,在其中加入延时函数,并在主函数中调用,以delay(1OO)为例。
设置工程选项Options,在Debugger栏中将Drivet选为Simulator,进行软件仿真。
在仿真环境C—SPY Debugger中,从菜单View 中调出Disassembly和Register窗口,前者显示编程软件根据C语言程序编译生成的汇编程序,在后者窗口中打开CPU Register子窗体,观察指令周期计数器CYCLE—COUNTER。
可以看到,delay()编译得到如下代码段:delav:001112 OF4C mov.w R12,R15OOlll4 0C4F mov.w R15.R12001116 3C53 add.w #0xFFFF.R12001118 0F93 tst.w R1500111A FB23 jne deIay单步执行,观察CYCI正COUNTER,发现每执行一条指令,CYCLECOUNTER的值加1,说明这5条指令各占用1个指令周期,循环体while()每执行一次需要5个指令周期,加上函数调用和函数返回各占用3个指令周期,delay(100)延时了5×100+6—506个指令周期。
只要知道指令周期,就能容易的计算出延时时长了。
延时函数因循环语句和编译器的不同,执行时间也有所不同,依照上述方法具体分析,可以达到灵活编程的目的。
MSP430的指令执行速度即指令所用的周期数,这里的时钟周期指主系统时钟MCLK的周期。
单片机上电后,如果不对时钟系统进行设置,默认800 kHz 的DCOCLK为MCLK和SMCLK的时钟源,LFXTl接32768 Hz晶体,工作在低频模式(XTS=O)作为ACLK的时钟源。
CPU的指令周期由MCLK决定,所以默认的指令周期就是1/800 kHz=1.25μs。
要得到lμs的指令周期需要调整DCO频率,即MCLK=1 MHz,只需进行如下设置:BCSCTLl=XT20FF+RSEL2;//关闭XT2振荡器,设定DCO频率为1 MHzDCOCTL=DCO2//使得单指令周期为lμs并不是说MSP430单片机软件延时最小的延时基准是lμs,当开启XT2=8 MHz高频振荡器,指令周期可以达到125 ns。
MSP430F4XX系列的单片机由于采用了增强型锁频环技术FLL+,可以将DCO频率倍增到40MHz,从而得到最快25 ns的指令周期。