您好,欢迎来电子发烧友网! ,新用户?[免费注册]

当前位置:电子发烧友网 > 图书频道 > 电子 > 《单片机原理与应用》 > 第8章 单片机高级程序设计

第2节 多路多点定时器

  8.2.1 原理图

  8.2.2 程序介绍

  1. 8255连接如上图,下面是8255初始化和控制灯和开关的几个函数:

  typedef unsigned char UINT8;

  typedef unsigned int UINT16;

  typedef unsigned long int UINT32;

  #include

  code unsigned char CLOSEOPEN[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

  code unsigned char CLOSEOPENB[7]={0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

  #define write_XDATA(address, value)

  (*((unsigned char volatile pdata*)address) = value)//写外部存储器

  /*15路开关控制、参数num表路数 flag表开关*/

  void Contral8255(UINT8 num,bit flag)

  {

  data UINT8 temp;

  if(num<7)

  {

  if(flag==1)

  {

  Pbvalue|=CLOSEOPENB[num];//&

  }

  else

  {

  temp=~CLOSEOPENB[num];

  Pbvalue&=temp;//|

  }

  write_XDATA(0xf9,Pbvalue);

  }

  else if(num<15)

  {

  if(flag==1)

  {

  Pcvalue |=CLOSEOPEN[num-7];//&

  }

  else

  {

  temp=~CLOSEOPEN[num-7];

  Pcvalue &=temp; //|

  }

  write_XDATA(0xfa,Pcvalue);

  }

  }

  /*每路指示灯的开关、num相应路数的指示灯 flag表亮灭*/

  void LedContral(UINT8 num,bit flag)

  {

  if(flag==1)

  {

  switch(num)

  {

  case 0:

  Led1=0;

  return;

  case 1:

  Led2=0;

  return;

  case 2:

  Led3=0;

  return;

  case 3:

  Led4=0;

  return;

  case 4:

  Led5=0;

  return;

  case 5:

  Led6=0;

  return;

  case 6:

  Pavalue &=0xfe;

  write_XDATA(0xf8, Pavalue);

  return;

  case 7:

  Pavalue &=0xfd;

  write_XDATA(0xf8, Pavalue);

  return;

  case 8:

  Pavalue &=0xfb;

  write_XDATA(0xf8, Pavalue);

  return;

  case 9:

  Pavalue &=0xf7;

  write_XDATA(0xf8, Pavalue);

  return;

  case 10:

  Pavalue &=0xef;

  write_XDATA(0xf8, Pavalue);

  return;

  case 11:

  Pavalue &=0xdf;

  write_XDATA(0xf8, Pavalue);

  return;

  case 12:

  Pavalue &=0xbf;

  write_XDATA(0xf8, Pavalue);

  return;

  case 13:

  Pavalue &=0x7f;

  write_XDATA(0xf8, Pavalue);

  return;

  case 14:

  Pbvalue&=0xfe;

  write_XDATA(0xf9, Pbvalue);

  return;

  default:

  break;

  }

  }

  else

  {

  switch(num)

  {

  case 0:

  Led1=1;

  return;

  case 1:

  Led2=1;

  return;

  case 2:

  Led3=1;

  return;

  case 3:

  Led4=1;

  return;

  case 4:

  Led5=1;

  return;

  case 5:

  Led6=1;

  return;

  case 6:

  Pavalue |= 0x01;

  write_XDATA(0xf8, Pavalue);

  return;

  case 7:

  Pavalue |= 0x02;

  write_XDATA(0xf8, Pavalue);

  return;

  case 8:

  Pavalue |=0x04;

  write_XDATA(0xf8, Pavalue);

  return;

  case 9:

  Pavalue |=0x08;

  write_XDATA(0xf8, Pavalue);

  return;

  case 10:

  Pavalue |=0x10;

  write_XDATA(0xf8, Pavalue);

  return;

  case 11:

  Pavalue |=0x20;

  write_XDATA(0xf8, Pavalue);

  return;

  case 12:

  Pavalue |=0x40;

  write_XDATA(0xf8, Pavalue);

  return;

  case 13:

  Pavalue |=0x80;

  write_XDATA(0xf8, Pavalue);

  return;

  case 14:

  Pbvalue |=0x01;

  write_XDATA(0xf9, Pbvalue);

  return;

  default:

  break;

  }

  }

  }

  void Init8255(void) //初始化8255

  {

  write_XDATA(0xfb,0x80);

  write_XDATA(0xf8,0x00);

  write_XDATA(0xf9,0x00);//0xfe

  write_XDATA(0xfa,0x00);//0xff

  P1 &=0x03;

  }

  //键盘扫描程序

  #define ESC 0x01

  #define MOVE 0x02

  #define DOWN 0x03

  #define ENTER 0x04

  #define UP 0x05

  以上为键值定义

  扫描函数如下:

  UINT8 KeyScan(void)//键盘扫描

  {

  data UINT8 key_val;

  data UINT8 current_key,k;

  static data UINT8 flag=0;

  key_val =P3;

  key_val &=0x3b;

  if(key_val==0x3b)

  {

  if(CloseFlag==0)

  {

  LCD_LED=LEDOFF;

  }

  return(0x00);

  }

  Delay1(500);

  key_val =P3;

  key_val &=0x3b;

  k=0;

  if(key_val==0x3b)

  {

  return(0x00);

  }

  while(1)

  {

  Delay1(400);

  current_key=P3;

  current_key &=0x3b;

  k++;

  ClearWatchDog();

  if(current_key==0x3b)

  {

  flag=0;

  break;

  }

  if(flag==0 && (k>250 && (current_key==0x33 || current_key==0x2b || current_key==0x1b)))

  {

  flag=1;

  break;

  }

  if(flag==1 && (k>50 && (current_key==0x33 || current_key==0x2b || current_key==0x1b)))

  break;

  }

  current_key =0x00;

  if(key_val == 0x3a) current_key = ESC; //返回

  else if(key_val == 0x39) current_key = ENTER; //开关

  else if(key_val == 0x33) current_key = DOWN;//移动

  else if(key_val == 0x2b) current_key = MOVE; //确认菜单

  else if(key_val == 0x1b) current_key = UP;//修改

  count2=0;

  if(current_key!=0 && Voice==1)

  {

  Beep1(1);

  }

  if(current_key!=0 && CloseFlag==0)

  {

  //SingleCmd(DISPLAY_ON);

  LCD_LED=LEDON;

  CloseFlag=1;

  changflag=1;

  return(0x00);

  }

  return(current_key);

  }

  2. LCD工作原理:

  Display control instruction

  相关定义:

  #define X_ADRESS 0xB8 /* Adress base for Page 0 */

  #define Y_ADRESS 0x40 /* Adress base for Y0 */

  #define START_LINE 0xC0 /* Adress base for line 0 */

  #define DISPLAY_ON 0x3F /* Turn display on */

  #define DISPLAY_OFF 0x3E /* Turn display off */

  #define LCD_DATA P0

  LCD相关函数:

  void InitLcd(void) //LCD初始化

  {

  LCD_DATA = 0;

  LCD_DI = 0;

  LCD_RW = 0;

  LCD_E = 0;

  LCD_CS1 = 0;

  LCD_CS2 = 0;

  SingleCmd(DISPLAY_OFF); /* Display OFF */

  SingleCmd(START_LINE);

  SingleCmd(X_ADRESS);

  SingleCmd(Y_ADRESS);

  SingleCmd(DISPLAY_ON); /* Display ON */

  }

  /*送命令函数*/

  void SingleCmd(UINT8 c)

  {

  LCD_E=0;

  LCD_DI=0;

  LCD_RW=1;

  LCD_CS1=1;

  LCD_CS2=1;

  LcdWaitBusy (); /* wait until LCD not busy */

  LCD_DI = 0; /* Instruction mode */

  LCD_RW = 0; /* Write mode */

  LCD_E = 1; /* Strobe */

  Delay1(2);

  LCD_DATA = c;/* outbyte */

  Delay1(3);

  LCD_E = 0;

  Delay1(5);

  LCD_CS1=0;

  LCD_CS2=0;

  }

  /*送数据函数*/

  void SingleData(UINT8 col,UINT8 c)

  {

  LCD_E=0;

  LCD_DI=0;

  LCD_RW=1;

  if(col<64)

  {

  LCD_CS1=1;

  }

  else

  {

  LCD_CS2=1;

  }

  LcdWaitBusy(); /* wait until LCD not busy */

  LCD_DI = 1; /* Data mode */

  LCD_RW = 0; /* write mode */

  LCD_DATA = c; /* outbyte */

  Delay1(1);

  LCD_E = 1; /* Strobe */

  Delay1(2);

  LCD_E = 0;

  Delay1(3);

  LCD_CS1=0;

  LCD_CS2=0;

  }

  /*LCD BUSY 等待*/

  void LcdWaitBusy (void)

  {

  LCD_DATA=0xFF; /* set LCD_DATA port in input mode */

  LCD_DI = 0; /* Instruction mode */

  LCD_RW = 1; /* Read mode */

  LCD_E = 1; /* strobe */

  Delay1(1);

  LCD_E = 0;

  while ( LCD_DATA & 0x7f == 0x80); /* mask the other status bits and test the BUSY bit */

  }

  /*清LCD显示*/

  void clearRAM(UINT8 startp,UINT8 endp)

  {

  data UINT8 u8Page,u8Column;

  for (u8Page = startp; u8Page < endp; u8Page++)

  {

  SetRAMAddr(u8Page,0x00);

  for (u8Column = 0; u8Column < 128; u8Column++)

  {

  SingleData(u8Column,0x00); /* erase a column */

  }

  }

  }

  /*设置显示位置*/

  void SetRAMAddr (UINT8 Page, UINT8 Col)

  {

  SingleCmd(X_ADRESS | Page); /* Set the page number */

  SingleCmd(Y_ADRESS |Col);

  }

  有关LCD其它函数如显示LOGO画面、菜单和图形数据字形数据等可到网上下载。

  //相关变量定义和函数说明

  data UINT8 Year=0,Month=1,Date=1,Week=6,Hour=12,Minute=0,Second=0;

  bit SecondFlag=0,MinuteFlag=0,HourFlag=0,DateFlag=0,MonthFlag=0,YearFlag=0;

  data UINT8 Function=1,BackNum=1,CloseFlag=1;

  data UINT8 Pic,Lang,Voice;

  data UINT8 Pbvalue=0xff,Pcvalue=0xff,Pavalue=0xff;

  data UINT16 count2=0;

  sbit LCD_CS1 = P2^1;

  sbit LCD_CS2 = P2^2;

  sbit LCD_RW = P2^4;

  sbit LCD_DI = P2^5;

  sbit LCD_E = P2^3;

  sbit key_out0 = P1^5;

  sbit MUNIC = P1^1;

  void InitLcd(void);

  void Delay1(UINT16 time);

  void LOGO(void);

  void Date_display(UINT8 w,UINT8 y,UINT8 m,UINT8 d,UINT8 n);

  void Time_display(UINT8 row,UINT8 h,UINT8 m,UINT8 s,UINT8 n);

  void clearRAM(unsigned char startpage,unsigned char stoppage);

  void SetRAMAddr(UINT8 Page, UINT8 Col);

  void Msingle_font_pattern(unsigned char *page_num, unsigned char page_y_in, unsigned char col_x_in,bit flag);

  void HzDisplay(unsigned char *page_num, unsigned char page_y_in, unsigned char col_x_in,bit flag);

  void Display_Line(unsigned char num, unsigned char page_y_in, unsigned char len,bit flag);

  void Second_moudel(void);

  void Display_Save(UINT8 row,UINT8 col);

  void Timer0_Init(void);

  void CPUInitial(void);

  void Num_Display(UINT8 num, unsigned char page_y_in, unsigned char col_x_in,bit flag);

  void SingleCmd(unsigned char c);

  void SingleData(UINT8 col,unsigned char c);

  void LcdWaitBusy(void);

  void Contral8255(UINT8 num,bit flag);

  void Beep1(UINT8 num);

  void LedContral(UINT8 num,bit flag);

  UINT8 KeyScan(void);

  sbit ISDA=P2^6;

  sbit ISCL=P2^7;

  sbit SPEAKER=P1^1;

  sbit Led1=P1^2;

  sbit Led2=P1^3;

  sbit Led3=P1^4;

  sbit Led4=P1^5;

  sbit Led5=P1^6;

  sbit Led6=P1^7;

  bit EEPROMByteWrite0(UINT16 addr,UINT8 value);

  UINT8 EEPROMByteRead0(UINT16 addr1);

  void I2cSentByte();

  void I2cStart(void);

  void I2cStop(void);

  extern void _nop_ (void);

  data UINT8 c,BeepFlag=0;

  bit ack;

  bit Contralflag=0;

  data UINT8 Luopencloseflag[15];

  data UINT8 count1;

  bit changflag=1;

  3. 24C512简介:

  它与其它24CXX系列一样,是一种I2C总线的存储器,64K*8的容量。原理在综合模块已讲解,下面给出相应的C程序。

  /*24c512 读写函数*/

  bit EEPROMByteWrite0(UINT16 addr,UINT8 value)

  {

  I2cStart();

  c=0xa0;

  I2cSentByte();

  if (ack==0)

  return(0);

  c=addr>>8;

  I2cSentByte();

  if (ack==0)

  return(0);

  c=addr;

  I2cSentByte();

  if (ack==0)

  return(0);

  c=value;

  I2cSentByte();

  if (ack==0)

  return(0);

  I2cStop();

  Delay1(50);

  return(1);

  }

  UINT8 EEPROMByteRead0(UINT16 addr1)

  {

  UINT8 bytedata,j;

  I2cStart();

  c=0xa0;

  I2cSentByte();

  if (ack==0)

  return(0);

  c=addr1>>8;

  I2cSentByte();

  if (ack==0)

  return(0);

  c=addr1;

  I2cSentByte();

  if (ack==0)

  return(0);

  I2cStart();

  c=0xa1;

  I2cSentByte();

  if (ack==0)

  return(0);

  ISDA=1;

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

  {

  _nop_();

  ISCL=0;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  ISCL=1;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  bytedata<<=1;

  if (ISDA)

  bytedata|=0x01;

  _nop_();

  _nop_();

  }

  ISCL=0;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  ISCL=1;

  I2cStop();

  return (bytedata);

  }

  void I2cStart(void)

  {

  ISDA=1;

  ISCL=1;

  _nop_();

  _nop_();

  _nop_();

  ISDA=0;

  _nop_();

  _nop_();

  _nop_();

  ISCL=0;

  _nop_();

  _nop_();

  }

  void I2cStop(void)

  {

  ISDA=0;

  ISCL=1;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  ISDA=1;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  ISCL=0;

  }

  void I2cSentByte()

  {

  data UINT8 temp1,temp2;

  for(temp1=0;temp1<8;temp1++)

  {

  temp2=c &0x80;

  if(temp2==0x80)

  ISDA=1;

  else

  ISDA=0;

  c<<=1;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  ISCL=1;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  ISCL=0;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  }

  _nop_();

  _nop_();

  ISDA=1;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  ISCL=1;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  if(ISDA==1)

  ack=0;

  else

  ack=1;

  ISCL=0;

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  }

  /*CPU 初始化、定时器初始化、定时器中断函数*/

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

  /* System Register of CPU Initialize */

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

  void CPUInitial(void)//CPU初始化

  {

  IE = 0x80;

  IP = 0x01;

  P0 = 0xff;

  P1 = 0xFF;

  P2 = 0xff;

  P3 = 0xff;

  }

  void Timer0_Init(void)//时钟0初始化

  {

  TMOD=0x01;

  TCON = 0x00;

  TL0 = 0xe0;

  TH0 = 0x3c;

  TR0 = 1 ;

  }

  void Delay1(UINT16 time) //延时函数

  {

  UINT16 i;

  for(i=0;i

  }

  void timer0(void) interrupt 1//时钟0中断处理

  {

  static data UINT8 count=0;

  //data UINT8 i;

  count++;

  count2++;

  if(count2>=24000)

  {

  CloseFlag=0;

  count2=0;

  }

  if(count>=40)

  {

  count=0;

  SecondFlag=1;

  Second_moudel();

  count1++;

  if(count1>=25 && BeepFlag==1)

  {

  Voice=1;

  BeepFlag=0;

  }

  else if(count1==31)

  {

  Voice=0;

  count1=0;

  }

  }

  TH0 = 0x3c;

  TL0 = 0xe0;

  TR0 = 1;

  }

  void Second_moudel(void)//秒表

  {

  Second=Second+1;

  if(Second==60)

  {

  Second=0;

  Minute++;

  MinuteFlag=1;

  if(Minute==60)

  {

  Minute=0;

  HourFlag=1;

  Hour++;

  if(Hour==24)

  {

  Hour=0;

  Date++;

  Week++;

  DateFlag=1;

  if(Week==7)

  Week=0;

  if(Month==4 || Month== 6 || Month==9 || Month==11)

  {

  if(Date>30)

  {

  Date=1;

  Month++;

  MonthFlag=1;

  }

  }

  else if(Month==2)

  {

  if(Year%4==0)

  {

  if(Date>29)

  {

  Date=1;

  Month++;

  MonthFlag=1;

  }

  }

  else

  {

  if(Date>28)

  {

  Date=1;

  Month++;

  MonthFlag=1;

  }

  }

  }

  else

  {

  if(Date>31)

  {

  Date=1;

  Month++;

  MonthFlag=1;

  }

  }

  if(Month>12)

  {

  Month=1;

  Year++;

  YearFlag=1;

  if(Year>99)

  Year=0;

  }

  }

  }

  }

  }

  UINT8 Weekjs(y,m,d)//星期计算

  {

  data UINT8 i,w;

  w=6;

  for(i=0;i

  {

  if(i%4==0)

  w+=2;

  else

  w+=1;

  }

  for(i=1;i

  {

  if(i==4 || i==6 || i==9 || i==11)

  w+=2;

  else if(i==2)

  {

  if(y%4==0)

  w+=1;

  }

  else

  w+=3;

  }

  w+=d;

  w-=1;

  w%=7;

  return(w);

  }

  /*主函数*/

  void main(void)

  {

  data UINT8 key,i,temp;

  data UINT8 k,j;

  data UINT16 addr;

  CPUInitial();

  Delay1(200);

  Beep1(3);

  InitLcd();

  Delay1(400);

  Pic=EEPROMByteRead0(0x20);

  Delay1(200);

  Lang=EEPROMByteRead0(0x21);

  Delay1(200);

  Voice=EEPROMByteRead0(0x22);

  Delay1(200);

  clearRAM(0,8);

  LOGO();

  temp=EEPROMByteRead0(0xffff);

  Delay1(2000);

  if(temp !=0x55)

  {

  for(k=0;k<0x30;k++)

  {

  EEPROMByteWrite0(k,0x01);

  Delay1(1000);

  }

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

  {

  for(k=0;k<15;k++)

  {

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

  {

  addr=(i*900+k*60+j)*6+0x30;

  EEPROMByteWrite0(addr,23);

  Delay1(1500);

  EEPROMByteWrite0(addr+1,59);

  Delay1(1500);

  EEPROMByteWrite0(addr+2,59);

  Delay1(1500);

  EEPROMByteWrite0(addr+3,23);

  Delay1(1500);

  EEPROMByteWrite0(addr+4,59);

  Delay1(1500);

  EEPROMByteWrite0(addr+5,59);

  Delay1(1500);

  }

  }

  }

  EEPROMByteWrite0(0xffff,0x55);

  }

  Init8255();

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

  Luopencloseflag[i]=0;

  Beep1(3);

  Timer0_Init();

  ET0 = 1;

  clearRAM(0,8);

  while(1)

  {

  switch(Function)

  {

  case 0:

  MainMenu();//主菜单选择ok

  changflag=1;

  break;

  case 1://时钟ok

  if(SecondFlag==1)

  {

  SecondFlag=0;

  if(changflag==1)

  {

  clearRAM(0,8);

  changflag=0;

  Time_display(5,Hour,Minute,Second,3);

  Date_display(Week,Year,Month,Date,3);

  }

  Num_Display(Second,5,80,0);

  if(MinuteFlag==1)

  {

  Num_Display(Minute,5,48,0);

  MinuteFlag=0;

  if(HourFlag==1)

  {

  Num_Display(Hour,5,16,0);

  HourFlag=0;

  if(DateFlag==1)

  {

  Num_Display(Date,3,80,0);

  DateFlag=0;

  Msingle_font_pattern(Time_offset[Week],0,32,0);

  if(MonthFlag==1)

  {

  Num_Display(Month,3,48,0);

  MonthFlag=0;

  if(YearFlag==1)

  {

  Num_Display(Year,3,16,0);

  YearFlag=0;

  }

  }

  }

  }

  }

  if(Second%2==1)

  {

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

  {

  if(Luopencloseflag[i]==1)

  LedContral(i,0);

  }

  }

  else

  OnOffContral();

  }

  key=KeyScan();

  if(key==ENTER)

  Function=0;

  break;

  case 2://日期时间设置ok

  DateTimeSet();

  break;

  case 3://定时参数设置

  ClockSet();

  break;

  case 4://本机设置

  SysSet();

  break;

  default:

  break;

  }

  }//while end

  }