|
寫這個程序是要實現,用按鍵+,-使電機調速,并在LCD段碼屏上
出現累加的兩位數字顯示。
****************************************
段式LCD驅動和電機調速實驗
外部晶體:12MHz
作者:dpj555
郵箱:
日期:2015.03.26
******************************************/
#include <reg52.h>
#include <stdio.h>
#define uint unsigned int
#define uchar unsigned char
/*管腳定義*/
sbit COM1=P1^7;
sbit COM2=P1^6;
sbit BI_4=P1^5;
sbit RTC_CLK=P1^4;
sbit RTC_IO=P1^3;
sbit RTC_RST=P1^2; //復用
/*P3口模式寄存器*/
sfr P3M1=0xb1;
sfr P3M0=0xb2;
/* 開機默認顯示*/
unsigned char ClockBuffer[8]={0x34,0x12,0x08,0x20,0x03,0x05,0x09};
/********************************
0~9的段碼查詢表
位序 D7 D6 D5 D4 D3 D2 D1 D0
段 A B C D E F G DOT
*********************************/
code unsigned char seg_code[10]={~0x03,~0x9f,~0x25,~0x0d,~0x99,~0x49,~0x41,~0x1f,~0x01,~0x09};
unsigned char ScanCoun=0; //動態掃描顯示位數計數器
unsigned char DisplayBuf[2]={1,2 }; //2位數字對應的顯示暫存
/*段碼緩沖區*/
unsigned char SegBuf[2]={0x00,0x00};//COM1、COM2 的段碼
bit bi_4a=0; //COM1對應的4a
bit bi_4b=0; //COM2對應的4b
/*延時*/
void dly(unsigned char x)
{unsigned char i;
for (i=0; i<x; i++);
}
/*ds1302寫1字節*/
void rtc_wt_byte(unsigned char sent_buf)
{unsigned char i;
for (i=0; i<8; i++)
{RTC_CLK=0;
if (sent_buf&0x01) RTC_IO=1;
else RTC_IO=0;
RTC_CLK=1;
dly(5);
sent_buf=sent_buf>>1;
}
RTC_CLK=0;
dly(5);
}
/*ds1302讀1字節*/
unsigned char rtc_rd_byte(void)
{unsigned char i,read_buf;
RTC_IO=1; //RTC_IO置1,保證為輸入狀態
for (i=0; i<8; i++)
{read_buf=read_buf>>1;
RTC_CLK=0;
dly(5);
if (RTC_IO) read_buf=read_buf|0x80;
else read_buf=read_buf&0x7f;
RTC_CLK=1;
dly(5);
}
RTC_CLK=0;
dly(5);
return read_buf;
}
/*ds1302寫入時間*/
void rtc_wr_time(unsigned char *p_wt_time)
{unsigned char i;
unsigned char tmp1;
dly(30);
RTC_RST=1;
rtc_wt_byte(0xbe); //burst寫入時間
for (i=0; i<8; i++)
{tmp1=*p_wt_time++;
rtc_wt_byte(tmp1);
}
RTC_CLK=0;
RTC_RST=0;
}
/*ds1302讀出時間*/
void rtc_rd_time(unsigned char *p_rd_time)
{unsigned char i;
unsigned char tmp1;
dly(30);
RTC_RST=1;
rtc_wt_byte(0xbf); //burst讀取時間
RTC_IO=1;
for (i=0; i<8; i++)
{tmp1=rtc_rd_byte();
*p_rd_time++=tmp1;
}
RTC_CLK=0;
RTC_RST=0;
}
/*ds1302初始化*/
void ini_rtc()
{RTC_CLK=0;
RTC_RST=0;
dly(30);
RTC_RST=1;
rtc_wt_byte(0x8e); //寫CONTROL寄存器
rtc_wt_byte(0x00); //值:去掉寫保護
RTC_RST=0; //復位
RTC_RST=1; //正常工作
rtc_wt_byte(0x90); //寫TRICKLE CHARGER寄存器
rtc_wt_byte(0xa9); //值:使能充電,串聯2個二極管,串聯2k歐姆的電阻
RTC_CLK=0;
RTC_RST=0;
}
/***********************************************************************************
把2位數字的SEG放到COM1、COM2 對應的段碼
LCD的管腳定義與LED不同,它不是一個COM對應一位數字,而是對應每個數字的一部分SEG
1 2 3 4 5 6 7 8
< 1f 1a 2f 2a 3f 3a 4f 4a > -- ---- COM1
< 1g 1b 2g 2b 2g 3b 4g 4b > -- ---- COM2
***********************************************************************************/
void Seg2Seg()
{unsigned char SegXX;
SegBuf[1]=0;
SegBuf[2]=0x08;
bi_4a=0;
bi_4b=0;
SegXX=seg_code[DisplayBuf[0]]; //第1位數字
if (SegXX&0x80) SegBuf[0]|=0x40;
if (SegXX&0x40) SegBuf[1]|=0x40;
if (SegXX&0x20) SegBuf[2]|=0x40;
if (SegXX&0x10) SegBuf[3]|=0x80;
if (SegXX&0x08) SegBuf[2]|=0x80;
if (SegXX&0x04) SegBuf[0]|=0x80;
if (SegXX&0x02) SegBuf[1]|=0x80;
if (SegXX&0x01) SegBuf[3]|=0x40;
SegXX=seg_code[DisplayBuf[1]]; //第2位數字
if (SegXX&0x80) SegBuf[0]|=0x10;
if (SegXX&0x40) SegBuf[1]|=0x10;
if (SegXX&0x20) SegBuf[2]|=0x10;
if (SegXX&0x10) SegBuf[3]|=0x20;
if (SegXX&0x08) SegBuf[2]|=0x20;
if (SegXX&0x04) SegBuf[0]|=0x20;
if (SegXX&0x02) SegBuf[1]|=0x20;
if (SegXX&0x01) SegBuf[3]|=0x10;
}
/*一個BCD碼轉化成兩個十進制數(如:0x79轉化成0x07和0x09)*/
BcdToDec(unsigned char BcdValue,unsigned char *pDecValue)
{//if (BcdValue>=0x9a||(BcdValue&0x0f)>=0x0a) return 0;
*pDecValue++=(BcdValue&0xf0)>>2;
*pDecValue=BcdValue&0x0f;
//return 1;
}
//初始化MCS51內部資源
InitInterResource()
{IE=0; //關全部中斷
TCON=0; //清全部中斷請求
IP=0; //清中斷優先級
TMOD=0x01; //T0工作方式1(16位定時器)
TH0=0x00; //T0定時器輔初值
TL0=0x00;
TR0=1; //允許T0定時
ET0=1; //允許T0中斷
EA=0; //關全局中斷
RTC_RST=0;
}
void main()
{
InitInterResource();
ini_rtc(); //初始化DS1302
rtc_wr_time(ClockBuffer); //寫入時間初始值
EA=1; //開全局中斷
while(1)
{
}
}
//定時器0中斷服務程序,5ms定時器,4位數碼管動態顯示驅動
void tmr0_p(void) interrupt 1
{
TL0=0x78; //重新定時5ms
TH0=0xec;
Seg2Seg();
P3M1=0x3c;
P3M0=0x00;
switch(ScanCoun) //動態掃描顯示
{
case 1: //COM1正向驅動
P1= SegBuf[1];
BI_4= bi_4a;
COM1=0;
P3M1=0x2c;
P3M0=0x00;
break;
case 2: //COM1反向驅動
P1= ~SegBuf[1];
BI_4= ~bi_4a;
COM1=1;
P3M1=0x2c;
P3M0=0x00;
break;
case 3: //COM2正向驅動
P1= SegBuf[2];
BI_4= bi_4b;
COM2=0;
P3M1=0x34;
P3M0=0x00;
break;
case 4: //COM2反向驅動
P1= ~SegBuf[2];
BI_4= ~bi_4b;
COM2=1;
P3M1=0x34;
P3M0=0x00;
break;
}
ScanCoun++; //下一位
if (ScanCoun>2) ScanCoun=0;
}
/*使單片機輸出PWM調速*/
/************************************************************************
為了使大家徹底掌握此方面,下面再給出一個復雜一點的程序,實現的功能為
通過按鍵使之可以在0到20級之間調速的程序。
/***********************************************************************/
/* 程序名:PWM直流電機調速 */
/* 晶振:11.00592 MHz CPU型號:STC12C2051 */
/* 直流電機的PWM波控制,可以通過按鍵控制正反轉并在0到20級之間調速 */
/*****************************************************************/
uchar time,count=50,flag=1;//低電平的占空比
sbit PWM1=P3^5;//PWM 通道 1,反轉脈沖
sbit PWM2=P3^7;//PWM 通道 2,正轉脈沖
sbit key_add=P1^1;//電機加速
sbit key_dec=P1^2;//電機減速
/************函數聲明**************/
void delayxms(uint z);
void Motor_turn();
void Motor_add();
void Motor_dec();
void timer0_init();
/****************延時處理**********************/
void delayxms(uint z)//延時xms程序
{
uint x,y;
for(y=z;x>0;x--)
for(y=110;y>0;y--);
/*********主函數********************/
timer0_init();
while(1)
Motor_turn();
Motor_add();
Motor_dec();
}
void Motor_add()//電機加速
{
if(key_add==0)
{
delayxms(2);//此處時間不能太長,否者會的中斷產生沖突
if(key_add==0)
{
count+=5;
if(count>=100)
{
count=0;
}
}
while(!key_add);
}
}
void Motor_dec()//電機加減速
{
if(key_dec==0)
{
delayxms(2);//此處時間不能太長,否者會的中斷產生沖突
if(key_dec==0)
{
count-=5;
if(count>=100)
{
count=0;
}
}
while(!key_dec);
}
}
/***********定時器0初始化***********/
void timer0_init()
{
TMOD=0x01; //定時器0工作于方式1
TH0=(65536-10)/256;
TL0=(65536-10)%256;
TR0=1;
ET0=1;
EA=1;
}
/**************定時0中斷處理******************/
void timer0_int() interrupt 1
{
TR0=0;//設置定時器初值期間,關閉定時器
TH0=(65536-10)/256;
TL0=(65536-10)%256;
TR0=1;
if(flag==1)//電機正轉
{
PWM1=0;
time++;
if(time<count)
{
PWM2=1;
}
else
PWM2=0;
if(time>=100)
{
time=0;
}
}
else //電機反轉
{
PWM2=0;
time++;
if(time<count)
{
PWM1=1;
}
else
PWM1=0;
if(time>=100)
{
time=0;
}
}
}
|
評分
-
查看全部評分
|