山东理工大学2000年12月单片机实训--按键计时器
emmm怎么说呢这个代码做的可以说不是很好,在网上东拼西凑写出来的代码。
我先把这个设计的要求说一下:设置一个按键,要求当按键按下时,单片机能够对按下时间进行计时,同时将该计时时间发送到1602液晶上同时通过RS232发送至上位机显示。
我们做完之后得到的效果是这样的:首先有两个按键控制这个单片机,第一个是摁下开始和暂停,第二个是长摁清零。然后还能通过RS232上传到上位机,当然你要选择一个接收工具来接收这个网上应该会有,或者说学校的机房里有。
但是吧,但是我们这个有瑕疵,就是接受数据的时候从头开始哈你摁一下现在数字已经开始走了,然后就一直上传到上位机数据,然后你再摁一下,就暂停了,上位机也不传数据了,然后在摁一下,又开始在上位机中有数据了。(很迷)。
首先我先把代码放上来
#include <msp430x14x.h>
#include "Config.h"
int second = 0, minute = 0, count = 0, flag = 0, a = 0, b = 0, c = 0;
unsigned char FlagLcd;
void Init(void);//声明初始化函数
char Data[20]; //发送的字符串void Init(void)
{UCTL0 &= ~SWRST; //USART控制寄存器UCTL0,SWRST=0x01,~SWRST=0xFE,将//UCTL0寄存器的第0位复位后,USART才能重新被允许UCTL0 =0X10; //UCTL0的第4位置1,设置数据长度为8位,第5位为0,设置1位停止位UBR00 = 0x03; //使用32768Hz晶体,波特率为9600UBR10 = 0x00;UMCTL0 = 0x4A;UTCTL0 = 0X10; //发送控制寄存器,第4位置1,选择辅助时钟ACLK1ME1 |= UTXE0 ; //设置模块允许寄存器ME1,UTXE0=0x80,设置ME1的第7位为1,//使USART模式发送允许P3SEL|=BIT4; //P3口选择寄存器的第4位置1,选择外围模块P3DIR|=BIT4; //P3口方向寄存器的第4位置1,选择输出
}
//*************************************************************************
// 初始化IO口子程序
//*************************************************************************
void Port_init()
{P4SEL = 0x00;P4DIR = 0xFF; //数据口输出模式P5SEL = 0x00;P5DIR|= BIT5 + BIT6 + BIT7; //控制口设置为输出模式P1SEL = 0x00; //P1普通IO功能P1DIR = 0xF0; //P1.0~P1.3输入模式,外部电路已接上拉电阻P1IE = 0x0f; //开启 位中断P1IES = 0x00; //上升沿触发中断P1IFG = 0x00; //软件清零中断标志寄存器
}//***********************************************************************
// 显示屏命令写入函数
//***********************************************************************
void LCD_write_com(unsigned char com)
{ RS_CLR;RW_CLR;EN_SET;DataPort = com; //命令写入端口delay_ms(5);EN_CLR;
}//***********************************************************************
// 显示屏数据写入函数
//***********************************************************************
void LCD_write_data(unsigned char data)
{RS_SET;RW_CLR;EN_SET;DataPort = data; //数据写入端口delay_ms(5);EN_CLR;
}//***********************************************************************
// 显示屏清空显示
//***********************************************************************
void LCD_clear(void)
{LCD_write_com(0x01); //清屏幕显示delay_ms(5);
}//***********************************************************************
// 显示屏字符串写入函数
//***********************************************************************
void LCD_write_str(unsigned char x,unsigned char y,int w)
{if (y == 0) {LCD_write_com(0x80 + x); //第一行显示}else {LCD_write_com(0xC0 + x); //第二行显示}LCD_write_data(48+w);}//***********************************************************************
// 显示屏单字符写入函数
//***********************************************************************
void LCD_write_char(unsigned char x,unsigned char y,unsigned char data)
{if (y == 0) {LCD_write_com(0x80 + x); //第一行显示}else {LCD_write_com(0xC0 + x); //第二行显示}LCD_write_data( data);
}//***********************************************************************
// 显示屏初始化函数
//***********************************************************************
void LCD_init(void)
{LCD_write_com(0x38); //显示模式设置 delay_ms(5);LCD_write_com(0x08); //显示关闭delay_ms(5);LCD_write_com(0x01); //显示清屏delay_ms(5);LCD_write_com(0x06); //显示光标移动设置delay_ms(5);LCD_write_com(0x0C); //显示开及光标设置delay_ms(5);
}
//***********************************************************************
// TIMERA初始化,设置为UP模式计数
//***********************************************************************
void TIMERA_Init(void) //UP模式计数,计数周期为CCR0+1
{TACTL |= TASSEL1 + TACLR + ID0 + ID1 + MC0 + TAIE; //SMCLK做时钟源,8分频,增加计数模式,开中断TACCR0 = 9999; //CCR0=9999,10ms中断一次
}
//***********************************************************************
// 关闭计时,暂停计数
//***********************************************************************
void TimerA_end(void)
{TACTL &= 0xfffd;
}
//**********************************************************************
// 扫描按键P1^2是否长按
//**********************************************************************
void GetKey()//长按,返回2;短按,返回1。
{unsigned char keyRetu=0; //返回的按键值static unsigned char s_keyState=0,keyTime=0; //按键状态,按键按下的时间switch (s_keyState){case 0:{if((P1IN&0x02)==0x00) //检测到有按键,转到状态1,相当于是消抖过程。{s_keyState=1;} }break;case 1:{if((P1IN&0x02)==0x00) //再次检测到有按键,转到状态2{s_keyState=2;keyTime=0; //清零按键时间计数器}else{s_keyState=0; //没有检测到按键,说明状态0检测到是一个抖动,重新转到状态0}}break;case 2:{if((P1IN&0x02)==0x02) //检测到按键松开{s_keyState=0; //状态转到状态0keyRetu=1; //输出1}else{if(++keyTime>=150) //按下时间>1s{s_keyState=3; //转到状态3keyTime=0; //清零按键时间计数器keyRetu=2; // 输出2}}}break;case 3:{if((P1IN&0x02)==0x02) //检测到按键松开{s_keyState=0; //状态转到状态0}else{s_keyState=3; //转到状态3}}break;}if(keyRetu==2){a = 0;b = 0;c = 0;count = 0;second = 0;minute = 0; }
}//***********************************************************************
// TIMERA中断服务程序,需要判断中断类型
//***********************************************************************
#pragma vector = TIMERA1_VECTOR
__interrupt void Timer_A(void)
{switch(TAIV) //需要判断中断的类型{case 2:break;case 4:break;case 10:count++;break; //设置标志位Flag}if(count==100) //100次为1秒{second++;count=0; }if(second == 60){minute++;second = 0;}GetKey();
}
//**********************************************************************
// P1口中断服务程序,需要判断
//**********************************************************************
#pragma vector = PORT1_VECTOR
__interrupt void P1_IRQ(void)
{switch(P1IFG&0x0F){case 0x01: { unsigned int i;Data[0]=c/10+48;Data[1]=c%10+48;Data[2]=0x3a;Data[3]=b/10+48;Data[4]=b%10+48;Data[5]=0x3a;Data[6]=a/10+48;Data[7]=a%10+48;Data[8]=10;for(i=0;i<=8;i++){TXBUF0=Data[i]; //向缓冲器送入待发送数据while((UTCTL0&0x01)==0); //发送缓冲器有待发数据时,UTCTL0的第0位复位,进入等待 }flag++;P1IFG=0x00;break;}default:P1IFG = 0x00;break; }
}//***********************************************************************
// 主程序
//***********************************************************************
void main(void)
{WDTCTL = WDTPW + WDTHOLD;Init(); //调用初始化函数WDT_Init(); //看门狗设置 Clock_Init(); //系统时钟设置Port_init(); //系统初始化,设置IO口属性delay_ms(100); //延时100msLCD_init(); //液晶参数初始化设置LCD_clear(); //清屏TIMERA_Init();_EINT();while (1) {//暂停或重置时进入此分支if(flag%2==0){LCD_write_str(0,1,c/10);LCD_write_str(1,1,c%10);LCD_write_char(2,1,0x3a);LCD_write_str(3,1,b/10);LCD_write_str(4,1,b%10);LCD_write_char(5,1,0x3a);LCD_write_str(6,1,a/10);LCD_write_str(7,1,a%10);LCD_write_str(0,0,c/10);LCD_write_str(1,0,c%10);LCD_write_char(2,0,0x3a);LCD_write_str(3,0,b/10);LCD_write_str(4,0,b%10);LCD_write_char(5,0,0x3a);LCD_write_str(6,0,a/10);LCD_write_str(7,0,a%10); }//计时过程中进入此分支else{count = a;second = b;minute = c;LCD_write_str(0,1,minute/10);LCD_write_str(1,1,minute%10);LCD_write_char(2,1,0x3a);LCD_write_str(3,1,second/10);LCD_write_str(4,1,second%10);LCD_write_char(5,1,0x3a);LCD_write_str(6,1,count/10);LCD_write_str(7,1,count%10); a = count;b = second;c = minute;}}
}
说一下在这里面引入了两个头文件首先是第一个#include <msp430x14x.h>这个文件是msp430系列的单片机自带的头文件,学校里系统教过单片机的如果是用IAR的话应该是知道这个头文件的,这里面的内容有点多就不一一叙述了。
其次就是#include "Config.h"这个头文件了下面我把这个头文件放在下面
//延时函数,IAR自带,经常使用到
#define CPU_F ((double)8000000) //外部高频晶振8MHZ
//#define CPU_F ((double)32768) //外部低频晶振32.768KHZ
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0)) //自定义数据结构,方便使用
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long//8个LED灯,连接在P6口,可通过断开电源停止使用,ADC使用时断开电源
#define LED8DIR P6DIR
#define LED8 P6OUT //P6口接LED灯,8个//4个独立按键连接在P10~P13
#define KeyPort P1IN //独立键盘接在P10~P13//串口波特率计算,当BRCLK=CPU_F时用下面的公式可以计算,否则要根据设置加入分频系数
#define baud 9600 //设置波特率的大小
#define baud_setting (uint)((ulong)CPU_F/((ulong)baud)) //波特率计算公式
#define baud_h (uchar)(baud_setting>>8) //提取高位
#define baud_l (uchar)(baud_setting) //低位//RS485控制管脚,CTR用于控制RS485处于收或者发状态
#define RS485_CTR1 P5OUT |= BIT2; //控制线置高,RS485发送状态
#define RS485_CTR0 P5OUT &= ~BIT2; //控制线置低,RS485接收状态//2.8寸TFT彩屏显示控制相关硬件配置
#define RS_CLR P5OUT &= ~BIT5 //RS置低
#define RS_SET P5OUT |= BIT5 //RS置高#define RW_CLR P5OUT &= ~BIT6 //RW置低
#define RW_SET P5OUT |= BIT6 //RW置高#define RD_CLR P5OUT &= ~BIT7 //E置低
#define RD_SET P5OUT |= BIT7 //E置高#define CS_CLR P5OUT &= ~BIT0 //CS置低
#define CS_SET P5OUT |= BIT0 //CS置高#define RST_CLR P5OUT &= ~BIT3 //RST置低
#define RST_SET P5OUT |= BIT3 //RST置高#define LE_CLR P5OUT &= ~BIT1 //LE置低
#define LE_SET P5OUT |= BIT1 //LE置高//2.8寸TFT彩屏触摸屏控制相关硬件配置
#define PEN_CLR P2OUT &= ~BIT0 //PEN置低,触碰触摸屏时,Penirq引脚由未触摸时的高电平变为低电平
#define PEN_SET P2OUT |= BIT0 //PEN置高
#define PEN (P2IN & 0x01) //P2.0输入的值#define TPDO_CLR P2OUT &= ~BIT1 //TPDO置低
#define TPDO_SET P2OUT |= BIT1 //TPDO置高
#define TPDOUT ((P2IN>>1)&0x01) //P2.1输入的值#define BUSY_CLR P2OUT &= ~BIT3 //BUSY置低
#define BUSY_SET P2OUT |= BIT3 //BUSY置高#define TPDI_CLR P2OUT &= ~BIT4 //TPDI置低
#define TPDI_SET P2OUT |= BIT4 //TPDI置高#define TPCS_CLR P2OUT &= ~BIT5 //TPCS置低
#define TPCS_SET P2OUT |= BIT5 //TPCS置高#define TPCLK_CLR P2OUT &= ~BIT6 //TPCLK置低
#define TPCLK_SET P2OUT |= BIT6 //TPCLK置高//彩屏/12864液晶/1602液晶的数据口,三液晶共用
#define DataDIR P4DIR //数据口方向
#define DataPort P4OUT //P4口为数据口//12864/1602液晶控制管脚
#define RS_CLR P5OUT &= ~BIT5 //RS置低
#define RS_SET P5OUT |= BIT5 //RS置高#define RW_CLR P5OUT &= ~BIT6 //RW置低
#define RW_SET P5OUT |= BIT6 //RW置高#define EN_CLR P5OUT &= ~BIT7 //E置低
#define EN_SET P5OUT |= BIT7 //E置高#define PSB_CLR P5OUT &= ~BIT0 //PSB置低,串口方式
#define PSB_SET P5OUT |= BIT0 //PSB置高,并口方式#define RESET_CLR P5OUT &= ~BIT1 //RST置低
#define RESET_SET P5OUT |= BIT1 //RST置高//12864应用指令集
#define CLEAR_SCREEN 0x01 //清屏指令:清屏且AC值为00H
#define AC_INIT 0x02 //将AC设置为00H。且游标移到原点位置
#define CURSE_ADD 0x06 //设定游标移到方向及图像整体移动方向(默认游标右移,图像整体不动)
#define FUN_MODE 0x30 //工作模式:8位基本指令集
#define DISPLAY_ON 0x0c //显示开,显示游标,且游标位置反白
#define DISPLAY_OFF 0x08 //显示关
#define CURSE_DIR 0x14 //游标向右移动:AC=AC+1
#define SET_CG_AC 0x40 //设置AC,范围为:00H~3FH
#define SET_DD_AC 0x80 //设置DDRAM AC
#define FUN_MODEK 0x36 //工作模式:8位扩展指令集//颜色代码,TFT显示用
#define White 0xFFFF //显示颜色代码
#define Black 0x0000
#define Blue 0x001F
#define Blue2 0x051F
#define Red 0xF800
#define Magenta 0xF81F
#define Green 0x07E0
#define Cyan 0x7FFF
#define Yellow 0xFFE0//NRF2401模块控制线
#define RF24L01_CE_0 P1OUT &=~BIT5 //CE在P15
#define RF24L01_CE_1 P1OUT |= BIT5 #define RF24L01_CSN_0 P2OUT &=~BIT7 //CS在P27
#define RF24L01_CSN_1 P2OUT |= BIT7 #define RF24L01_SCK_0 P3OUT &=~BIT3 //SCK在P33
#define RF24L01_SCK_1 P3OUT |= BIT3 #define RF24L01_MISO_0 P3OUT &=~BIT2 //MISO在P32
#define RF24L01_MISO_1 P3OUT |= BIT2#define RF24L01_MOSI_0 P3OUT &=~BIT1 //MOSI在P31
#define RF24L01_MOSI_1 P3OUT |= BIT1#define RF24L01_IRQ_0 P1OUT &=~BIT4 //IRQ在P14
#define RF24L01_IRQ_1 P1OUT |= BIT4//DS18B20控制脚,单脚控制
#define DQ_IN P1DIR &= ~BIT7 //设置输入,DS18B20接单片机P53口
#define DQ_OUT P1DIR |= BIT7 //设置输出
#define DQ_CLR P1OUT &= ~BIT7 //置低电平
#define DQ_SET P1OUT |= BIT7 //置高电平
#define DQ_R P1IN & BIT7 //读电平//红外接收头H1838控制脚,单脚控制
#define RED_IN P1DIR &= ~BIT6 //设置输入,红外接收头接单片机PE3口
#define RED_OUT P1DIR |= BIT6 //设置输出
#define RED_L P1OUT &= ~BIT6 //置低电平
#define RED_H P1OUT |= BIT6 //置高电平
#define RED_R (P1IN & BIT6) //读电平//***********************************************************************
// 系统时钟初始化,外部8M晶振
//***********************************************************************
void Clock_Init()
{uchar i;BCSCTL1&=~XT2OFF; //打开XT2振荡器BCSCTL2|=SELM1+SELS; //MCLK为8MHZ,SMCLK为8MHZdo{IFG1&=~OFIFG; //清楚振荡器错误标志for(i=0;i<100;i++)_NOP();}while((IFG1&OFIFG)!=0); //如果标志位1,则继续循环等待IFG1&=~OFIFG;
}//***********************************************************************
// 系统时钟初始化,内部RC晶振
//***********************************************************************
void Clock_Init_Inc()
{// DCOCTL = DCO0 + DCO1 + DCO2; // Max DCO// BCSCTL1 = RSEL0 + RSEL1 + RSEL2; // XT2on, max RSELDCOCTL = 0x60 + 0x00; //DCO约3MHZ,3030KHZBCSCTL1 = DIVA_0 + 0x07;BCSCTL2 = SELM_2 + DIVM_0 + SELS + DIVS_0;
}//***********************************************************************
// 系统时钟初始化,外部32.768K晶振
//***********************************************************************
void Clock_Init_Ex32768()
{uchar i;BCSCTL2|=SELM1 + SELM0 + SELS; //MCLK为32.768KHZ,SMCLK为8MHZdo{IFG1&=~OFIFG; //清楚振荡器错误标志for(i=0;i<100;i++)_NOP();}while((IFG1&OFIFG)!=0); //如果标志位1,则继续循环等待IFG1&=~OFIFG;
}//***********************************************************************
// MSP430内部看门狗初始化
//***********************************************************************
void WDT_Init()
{WDTCTL = WDTPW + WDTHOLD; //关闭看门狗
}
就这样单片的实训的代码就全都放在下面了但是这个代码是有问题的,也是我们没有解决的问题,其中有一个非常大的问题,就是上面说的上传到上位机的问题。
山东理工大学2000年12月单片机实训--按键计时器相关推荐
- Python 计算在1901年1月1日至2000年12月31日间共有多少个星期天落在每月的第一天上
题目内容: 根据下列信息计算在1901年1月1日至2000年12月31日间共有多少个星期天落在每月的第一天上? a) 1900.1.1是星期一 b) 1月,3月,5月,7月,8月,10月和12月是31 ...
- 【练习题】根据下列信息计算在1901年1月1日至2000年12月31日间共有多少个星期天落在每月的第一天上?
题目内容: 根据下列信息计算在1901年1月1日至2000年12月31日间共有多少个星期天落在每月的第一天上? a) 1900.1.1是星期一 b) 1月,3月,5月,7月,8月,10月和1 ...
- python输出一年有多少天多少时分秒_python:计算在1901年1月1日至2000年12月31日间共有多少个星期天落在每月的第一天上...
# -*- coding: UTF-8 -*- """ Created on 2017/4/2 @author: cat """ impor ...
- 根据下列信息计算在1901年1月1日至2000年12月31日间共有多少个星期天落在每月的第一天上?
-- coding: utf-8 -- """ Created on Sun Sep 06 08:51:53 2015 @author: MONKEY 根据下列信息计算在 ...
- 昆明理工大学毕业的英语及计算机资格怎么填,昆明理工大学2019年12月四六级报名流程...
2019年下半年大学英语四六级考试报名于9月开始.具体各省大学英语四六级笔试.大学英语四六级口试报名时间.报名官网均不一致,英语四六级考试报名网站除少数省份有统一报名入口外,一般采用的是以院校为考点. ...
- python:计算在1901年1月1日至2000年12月31日间共有多少个星期天落在每月的第一天上
根据下列信息计算在1901年1月1日至2000年12月31日间共有多少个星期天落在每月的第一天上? a) 1900.1.1是星期一 b) 1月,3月,5月,7月,8月,10月和12月是31天 c) 4 ...
- 单片机8位抢答器实训机电报告_16路抢答器单片机实训报告.docx
<16路抢答器单片机实训报告.docx>由会员分享,可在线阅读,更多相关<16路抢答器单片机实训报告.docx(33页珍藏版)>请在微传网上搜索. 1.四川信息职业技术学院课程 ...
- 计算机单片机实训报告,计算器单片机实训报告.doc
计算器单片机实训报告 重庆电力高等专科学校 单片机实训报告 简易计算器 专业:电子信息工程技术 班级:信息1212 组员:张忠艳 学号:201203020207 组员:王传胜 学号:201203020 ...
- 计算机单片机实训报告,单片机实训总结
单片机实训总结 总结在一个时期.一个年度.一个阶段对学习和工作生活等情况加以回顾和分析的一种书面材料,它可以给我们下一阶段的学习和工作生活做指导,快快来写一份总结吧.你所见过的总结应该是什么样的?下面 ...
最新文章
- 史上最全的高可用服务系统线上问题排查工具单(一)
- R语言使用psych包的fa函数对指定数据集进行因子分析(输入数据为相关性矩阵)、使用rotate参数指定进行斜交旋转提取因子、使用factor.plot函数可视化斜交旋转因子分析、并解读可视化图形
- Win7安装Docker
- ubuntu14.6 密码重置_已迁移
- [Windows子系统] Ubuntu18.04安装及换源
- 请你讲一讲JavaScript有哪些数据类型, 数据类型判断有哪些方法?
- 滴滴产品总监:如何合理设计弹窗以保证流畅的用户体验?
- mysql 迁移表时忽略索引_Mysql迁移新环境索引损坏
- Elasticsearch及相关插件的安装
- ValueError: Variable conv1/weights already exists.
- 蓬荜生辉的意思是什么?蓬荜生辉用在什么场合?
- centos7自带流量监控软件iftop
- HttpClient、HttpURLConnection、OKHttp和Volley
- 富士施乐3065扫描教程_富士施乐打印机3065怎么连接电脑扫描
- spark GBT算法
- 洛谷 U84985 Seaway找路
- Kotlin 学习笔记(三)—— Kotlin 的动态代理你会写吗
- 简单好用的在线P图工具,一定记得收藏
- ORA-03135: Connection Lost Contact 数据库丢失联系
- CTFHub技能树 Web-XSS 详解