stm8 软件模拟IIC驱动PCF8563T,NOKIA5110液晶显示

调试stm8硬件IIC,弄了几天,搞得人头大,一直程序就是卡在  while((I2C_SR1&0x02))这里,数据手册和网上的各种帖子基本都看了,程序都试了,ARF位也设置了,还是调试不通,最后没办法只能使用软件模拟IIC了。

这次使用软件模拟IIC驱动PCF8563T,这个时钟芯片。其实软件模拟也不难。

我们就来直接看代码吧。具体的实验现象,没有图片,现在硬件也拆了,但是程序都是验证过了的。通过一个NOKIA5110液晶屏显示出来时间数据。

#include "IOSTM8S105K4.h"

#define u16 unsigned int 
#define u8  unsigned char 
u8 i;

void delay_ms(u16 xms);
void System_Init(void)
{
   CLK_SWR = 0xE1;  //选择高速内部时钟HSI为主时钟
   CLK_ICKR |= 0x01;  //高速内部HSI时钟使能
   while(!(CLK_ICKR&0x02)); //等待内部高速HSI就绪
   CLK_CKDIVR = 0x18;   // Fhsi = Fhsi = Fcpu = Fmaster = 2MHz 
}

void Timer4_init(u8 psc,u8 arr )
{
   CLK_PCKENR1 |= 0x10;  //打开TIM4时钟 = Fmaster = 2MHz
   TIM4_EGR = 0x01;  //计数器重新初始化并产生寄存器更新
   TIM4_PSCR = psc; //分频器时钟为2MHz/psc
//   TIM4_CNTR = arr;  //计数器值
   TIM4_ARR = arr;   //自动重载值
   TIM4_CR1 = 0x01;  //使能计数器
   TIM4_IER = 0x01;  //使能更新中断
   asm("rim");  //开全局中断
}

void LCD_CLK(u8 x)
{
  PC_DDR |= 0x08;
  PC_CR1 |= 0x08;
  PC_CR2 |= 0x00;
  if(x == 1)
    PC_ODR |= 0x08;
  else if(x == 0)PC_ODR &= 0xF7;
}
void LCD_DIN(u8 x)
{
  PC_DDR |= 0x04;
  PC_CR1 |= 0x04;
  PC_CR2 |= 0x00;
  if(x == 1)
    PC_ODR |= 0x04;
  else if(x == 0)PC_ODR &= 0xFB;
}
void LCD_DC(u8 x)
{
  PC_DDR |= 0x02;
  PC_CR1 |= 0x02;
  PC_CR2 |= 0x00;
  if(x == 1)
    PC_ODR |= 0x02;
  else if(x == 0)PC_ODR &= 0xFD;
}
void LCD_CE(u8 x)
{
  PE_DDR|=0x20;
  PE_CR1|=0x20;
  PE_CR2|=0x00;
  if(x == 1)
    PE_ODR |= 0x20;
  else if(x == 0)PE_ODR &= 0xDF;
}
void LCD_RST(u8 x)
{
  PB_DDR|=0x01;
  PB_CR1|=0x01;
  PB_CR2|=0x00;
  if(x == 1)
    PB_ODR |= 0x01;
  else if(x == 0)PB_ODR &= 0xFE;
}
void LCD_BL(u8 x)
{
  PC_DDR|=0x10;
  PC_CR1|=0x10;
  PC_CR2|=0x00;
  if(x == 1)
    PC_ODR |= 0x10;
  else if(x == 0)PC_ODR &= 0xEF;
}
/*--------------------------------------------------------------*/
//指令宏定义
#define X_Col_Addr     0x80		//定位到第0列指令(列起始地址)(0 - 83)
#define Y_Page_Addr    0x40		//定位到第0页指令(页起始地址)(0 - 5)

/*------------------------------------------
//数据接口定义
#define LCD_CLK  PC_ODR_ODR3     //串行时钟		//上升沿写入数据
#define LCD_DIN  PC_ODR_ODR2     //串行数据输入		//先高后低
#define LCD_DC   PC_ODR_ODR1     //数据指令控制端	//高电平数据,低电平指令
#define LCD_CS   PE_ODR_ODR5     //片选使能		//低电平有效
#define LCD_RST  PB_ODR_ODR0     //LCD复位端		//低电平复位
--------------------*/

/*--------------------------------------------------------------*/
//功能宏定义
//液晶复位
#define LCD_reset_hard	LCD_RST(0); delay_ms(1); LCD_RST(1);delay_ms(1)	//硬件复位
#define LCD_reset_soft	LCD_reset_5510()			//软件复位
//液晶显示控制(不影响DDRAM)
#define LCD_show_blank		LCD_write_cmd(0x08)		//显示空白
#define LCD_show_normal		LCD_write_cmd(0x0c)		//正常显示
#define LCD_show_black		LCD_write_cmd(0x09)		//显示全黑
#define LCD_show_inverse 	LCD_write_cmd(0x0d)		//反色显示
//便于理解
#define LCD_write_cmd(cmd)	LCD_write_byte(cmd, 0)	//写入指令
#define LCD_write_dat(dat)	LCD_write_byte(dat, 1)	//写入数据


/*--------------------------------------------------------------*/
//函数声明(私有)
void LCD_write_byte(u8 wbyte, u8 dat_cmd);//写入字节
void LCD_reset_5510(void);										//复位LCD5510


/*--------------------------------------------------------------*/
//函数声明(公有)
/*--------------------------------------------------------------*/
//清屏参数(清DDRAM)
void LCD_clr_scr(void);


/*--------------------------------------------------------------*/
//液晶字节定位(1*1)
//液晶规划:
//x: 0 - 83
//y: 0 - 5
void LCD_pos_byte(u8 x, u8 y);


/*--------------------------------------------------------------*/
//显示清行
//num:	0 - 5
void LCD_clr_row(u8 num);


/*--------------------------------------------------------------*/
//液晶字符输出(6*8字体)
//x: 0 - 13
//y: 0 - 5
void LCD_printc(u8 x, u8 y, u8 c_dat);


/*--------------------------------------------------------------*/
//液晶字符串输出(6*8字体)
//x: 0 - 13
//y: 0 - 5
void LCD_prints(u8 x, u8 y, u8 *s_dat);


/*--------------------------------------------------------------*/
//液晶字符串输出,自动换行(6*8字体)
//x: 0 - 13
//y: 0 - 5
void LCD_printsl(u8 x, u8 y, u8 *s_dat);


/*--------------------------------------------------------------*/
//液晶汉字输出(16*16字体)
//查表显示输出
//取码规则:	低位在前, 列行扫描, 阴码(1-亮, 0-灭)
//x: 0 - 4
//y: 0 - 2
void LCD_showch(u8 x, u8 y, u8  *dat);


/*--------------------------------------------------------------*/
//液晶汉字词组输出(16*16字体)
//查表显示输出
//取码规则:	低位在前, 列行扫描, 阴码(1-亮, 0-灭)
//x: 0 - 4
//y: 0 - 2
//一行最多5个
void LCD_showsh(u8 x, u8 y, u8  *dat);


/*--------------------------------------------------------------*/
//显示84X48图片
//取码规则:	低位在前, 列行扫描, 阴码(1-亮, 0-灭)
void LCD_picture(u8  *img_dat);


/*--------------------------------------------------------------*/
//定位显示指定大小图片
//取码规则:	低位在前, 列行扫描, 阴码(1-亮, 0-灭)
//pag:	0 - 5			页坐标
//col:  0 - 83			列坐标
//x:	0 - (83-col)	图片宽
//y:	0 - (47-pag*8)	图片高
void LCD_pos_picture(u8 col, u8 pag, u8 x, u8 y, u8  *img_dat);


/*--------------------------------------------------------------*/ 
//定位输出数字
//x: 0 - 13
//y: 0 - 5
//num: 0 - 65535	要显示的数字
//num_u8: 0 - 5	数字的位数
void LCD_printn(u8 x, u8 y, u16 num, u8 num_u8);


/*--------------------------------------------------------------*/
//初始化LCD5510
void LCD5510_Init(void);				

// ------------------  汉字字模的数据结构定义 ------------------------ //
typedef struct typFNT_GB16                 // 汉字字模数据结构
{
       u8 Index[2];               // 汉字内码索引
       u8 Msk[32];                       // 点阵码数据
}typFNT_GB16;

/
// 汉字字模表                                                          //
// 汉字库: 宋体16.dot 纵向取模下高位,数据排列:从左到右从上到下         //
/
struct typFNT_GB16  GB_16[] =          // 数据表
{
"我", 0x20,0x24,0x24,0x24,0xFE,0x23,0x22,0x20,0xFF,0x20,0x22,0xAC,0x20,0x30,0x20,0x00,
      0x00,0x08,0x48,0x84,0x7F,0x02,0x21,0x10,0x09,0x06,0x1A,0x61,0x80,0xE0,0x00,0x00,

"心", 0x00,0x00,0xC0,0x00,0xF0,0x00,0x01,0x02,0x1C,0x08,0x00,0x00,0x40,0x80,0x00,0x00,
      0x04,0x02,0x01,0x00,0x3F,0x40,0x40,0x40,0x40,0x40,0x40,0x70,0x00,0x00,0x07,0x00,

"永", 0x00,0x40,0x40,0x48,0x48,0xC8,0x09,0xFA,0x40,0x80,0x40,0x20,0x30,0x00,0x00,0x00,
      0x00,0x20,0x10,0x08,0x06,0x41,0x80,0x7F,0x00,0x01,0x06,0x08,0x10,0x30,0x10,0x00,

"恒", 0x80,0x70,0x00,0xFF,0x10,0x22,0xF2,0x92,0x92,0x92,0x92,0x92,0xFB,0x12,0x00,0x00,
      0x00,0x00,0x00,0xFF,0x20,0x20,0x27,0x24,0x24,0x24,0x24,0x24,0x27,0x30,0x20,0x00,

"之", 0x00,0x10,0x10,0x10,0x10,0x10,0x11,0x16,0x10,0x90,0x50,0x30,0x10,0x00,0x00,0x00,
      0x00,0x20,0x10,0x10,0x28,0x48,0x44,0x42,0x41,0x40,0x40,0x40,0x40,0x60,0x20,0x00,

"★", 0x00,0x20,0x60,0xE0,0xE0,0xE0,0xF0,0xFC,0xFF,0xFC,0xF0,0xE0,0xE0,0xE0,0x60,0x20,
      0x00,0x00,0x40,0x30,0x3D,0x1F,0x1F,0x0F,0x07,0x0F,0x1F,0x1F,0x3D,0x30,0x40,0x00
};

// 汉字表:
// 我心永恒★

#define GB_16_num	sizeof(GB_16) / 34				//汉字个数


/*--------------------------------------------------------------
//字库码的引索
  (0)  !(1)  "(2)  #(3)  $(4)  %(5)  &(6)  '(7)
 ((8)  )(9)  *(10) +(11) ,(12) -(13) .(14) /(15)
 0(16) 1(17) 2(18) 3(19) 4(20) 5(21) 6(22) 7(23)
 8(24) 9(25) :(26) ;(27) <(28) =(29) >(30) ?(31)
 @(32) A(33) B(34) C(35) D(36) E(37) F(38) G(39)
 H(40) I(41) J(42) K(43) L(44) M(45) N(46) O(47)
 P(48) Q(49) R(50) S(51) T(52) U(53) V(54) W(55)
 X(56) Y(57) Z(58) [(59) \(60) ](61) ^(62) _(63)
 `(64) a(65) b(66) c(67) d(68) e(69) f(70) g(71)
 h(72) i(73) j(74) k(75) l(76) m(77) n(78) o(79)
 p(80) q(81) r(82) s(83) t(84) u(85) v(86) w(87)
 x(88) y(89) z(90) {(91) |(92) }(93) ~(94)
--------------------------------------------------------------*/


/*--------------------------------------------------------------*/
//	  字体:	LCD1602字体
//取码规则:	低位在前, 列行扫描, 阴码(1-亮, 0-灭)
//查表方法: 要显示的ASCII码-32就可以得到字库码的指针
u8  Font_[][6] = {
{0x00,0x00,0x00,0x00,0x00,0x00},// (0)
{0x00,0x00,0x00,0x4F,0x00,0x00},//!(1)
{0x00,0x00,0x07,0x00,0x07,0x00},//"(2)
{0x00,0x14,0x7F,0x14,0x7F,0x14},//#(3)
{0x00,0x24,0x2A,0x7F,0x2A,0x12},//$(4)
{0x00,0x23,0x13,0x08,0x64,0x62},//%(5)
{0x00,0x36,0x49,0x55,0x22,0x50},//&(6)
{0x00,0x00,0x05,0x03,0x00,0x00},//'(7)
{0x00,0x00,0x1C,0x22,0x41,0x00},//((8)
{0x00,0x00,0x41,0x22,0x1C,0x00},//)(9)
{0x00,0x14,0x08,0x3E,0x08,0x14},//*(10)
{0x00,0x08,0x08,0x3E,0x08,0x08},//+(11)
{0x00,0x00,0x50,0x30,0x00,0x00},//,(12)
{0x00,0x08,0x08,0x08,0x08,0x08},//-(13)
{0x00,0x00,0x60,0x60,0x00,0x00},//.(14)
{0x00,0x20,0x10,0x08,0x04,0x02},///(15)
{0x00,0x3E,0x51,0x49,0x45,0x3E},//0(16)
{0x00,0x00,0x42,0x7F,0x40,0x00},//1(17)
{0x00,0x42,0x61,0x51,0x49,0x46},//2(18)
{0x00,0x21,0x41,0x45,0x4B,0x31},//3(19)
{0x00,0x18,0x14,0x12,0x7F,0x10},//4(20)
{0x00,0x27,0x45,0x45,0x45,0x39},//5(21)
{0x00,0x3C,0x4A,0x49,0x49,0x30},//6(22)
{0x00,0x01,0x71,0x09,0x05,0x03},//7(23)
{0x00,0x36,0x49,0x49,0x49,0x36},//8(24)
{0x00,0x06,0x49,0x49,0x29,0x1E},//9(25)
{0x00,0x00,0x36,0x36,0x00,0x00},//:(26)
{0x00,0x00,0x56,0x36,0x00,0x00},//;(27)
{0x00,0x08,0x14,0x22,0x41,0x00},//<(28)
{0x00,0x14,0x14,0x14,0x14,0x14},//=(29)
{0x00,0x00,0x41,0x22,0x14,0x08},//>(30)
{0x00,0x02,0x01,0x51,0x09,0x06},//?(31)
{0x00,0x32,0x49,0x79,0x41,0x3E},//@(32)
{0x00,0x7E,0x11,0x11,0x11,0x7E},//A(33)
{0x00,0x7F,0x49,0x49,0x49,0x3E},//B(34)
{0x00,0x3E,0x41,0x41,0x41,0x22},//C(35)
{0x00,0x7F,0x41,0x41,0x22,0x1C},//D(36)
{0x00,0x7F,0x49,0x49,0x49,0x41},//E(37)
{0x00,0x7F,0x09,0x09,0x09,0x01},//F(38)
{0x00,0x3E,0x41,0x49,0x49,0x7A},//G(39)
{0x00,0x7F,0x08,0x08,0x08,0x7F},//H(40)
{0x00,0x00,0x41,0x7F,0x41,0x00},//I(41)
{0x00,0x20,0x40,0x41,0x3F,0x01},//J(42)
{0x00,0x7F,0x08,0x14,0x22,0x41},//K(43)
{0x00,0x7F,0x40,0x40,0x40,0x40},//L(44)
{0x00,0x7F,0x02,0x04,0x02,0x7F},//M(45)
{0x00,0x7F,0x04,0x08,0x10,0x7F},//N(46)
{0x00,0x3E,0x41,0x41,0x41,0x3E},//O(47)
{0x00,0x7F,0x09,0x09,0x09,0x06},//P(48)
{0x00,0x3E,0x41,0x51,0x21,0x5E},//Q(49)
{0x00,0x7F,0x09,0x19,0x29,0x46},//R(50)
{0x00,0x46,0x49,0x49,0x49,0x31},//S(51)
{0x00,0x01,0x01,0x7F,0x01,0x01},//T(52)
{0x00,0x3F,0x40,0x40,0x40,0x3F},//U(53)
{0x00,0x1F,0x20,0x40,0x20,0x1F},//V(54)
{0x00,0x3F,0x40,0x38,0x40,0x3F},//W(55)
{0x00,0x63,0x14,0x08,0x14,0x63},//X(56)
{0x00,0x03,0x04,0x78,0x04,0x03},//Y(57)
{0x00,0x61,0x51,0x49,0x45,0x43},//Z(58)
{0x00,0x00,0x7F,0x41,0x41,0x00},//[(59)
{0x00,0x15,0x16,0x7C,0x16,0x15},//\(60)
{0x00,0x00,0x41,0x41,0x7F,0x00},//](61)
{0x00,0x04,0x02,0x01,0x02,0x04},//^(62)
{0x00,0x40,0x40,0x40,0x40,0x40},//_(63)
{0x00,0x00,0x01,0x02,0x04,0x00},//`(64)
{0x00,0x20,0x54,0x54,0x54,0x78},//a(65)
{0x00,0x7F,0x48,0x44,0x44,0x38},//b(66)
{0x00,0x38,0x44,0x44,0x44,0x20},//c(67)
{0x00,0x38,0x44,0x44,0x48,0x7F},//d(68)
{0x00,0x38,0x54,0x54,0x54,0x18},//e(69)
{0x00,0x08,0x7E,0x09,0x01,0x02},//f(70)
{0x00,0x0C,0x52,0x52,0x52,0x3E},//g(71)
{0x00,0x7F,0x08,0x04,0x04,0x78},//h(72)
{0x00,0x00,0x44,0x7D,0x40,0x00},//i(73)
{0x00,0x20,0x40,0x44,0x3D,0x00},//j(74)
{0x00,0x7F,0x10,0x28,0x44,0x00},//k(75)
{0x00,0x00,0x41,0x7F,0x40,0x00},//l(76)
{0x00,0x7E,0x02,0x0C,0x02,0x7C},//m(77)
{0x00,0x7E,0x04,0x02,0x02,0x7C},//n(78)
{0x00,0x38,0x44,0x44,0x44,0x38},//o(79)
{0x00,0x7C,0x14,0x14,0x14,0x08},//p(80)
{0x00,0x08,0x14,0x14,0x18,0x7C},//q(81)
{0x00,0x7C,0x08,0x04,0x04,0x08},//r(82)
{0x00,0x48,0x54,0x54,0x54,0x20},//s(83)
{0x00,0x04,0x3F,0x44,0x40,0x20},//t(84)
{0x00,0x3C,0x40,0x40,0x20,0x7C},//u(85)
{0x00,0x1C,0x20,0x40,0x20,0x1C},//v(86)
{0x00,0x3C,0x40,0x30,0x40,0x3C},//w(87)
{0x00,0x44,0x28,0x10,0x28,0x44},//x(88)
{0x00,0x0C,0x50,0x50,0x50,0x3C},//y(89)
{0x00,0x44,0x64,0x54,0x4C,0x44},//z(90)
{0x00,0x00,0x08,0x36,0x41,0x00},//{(91)
{0x00,0x00,0x00,0x7F,0x00,0x00},//|(92)
{0x00,0x00,0x41,0x36,0x08,0x00},//}(93)
{0x00,0x08,0x04,0x08,0x10,0x08},//~(94)
{0x00,0x08,0x08,0x2A,0x1C,0x08},//→(127)
{0x00,0x08,0x1C,0x2A,0x08,0x08},//←(128)
{0x00,0x04,0x02,0x7F,0x02,0x04},//↑(129)
{0x00,0x10,0x20,0x7F,0x20,0x10},//↓(130)
{0x00,0x1C,0x2A,0x32,0x2A,0x1C},//笑面(131)
{0x00,0x1C,0x22,0x44,0x22,0x1C}};//爱心(132)

/*--------------------------------------------------------------*/

/*延时xms函数@ HSI 2MHz*/
void delay_ms(u16 xms)
{
  u16 i,j;
  for(i=xms;i>0;i--)
   for(j=330;j>0;j--)
   {
      asm("nop");
   }
}
/*硬件驱动NOKIA5110液晶代码*/
/*void Spi_Init(void)
{
  CLK_PCKENR1 |= 0x02;  //打开SPI时钟
  /*PC6、PC5设置为输出,最大10MHz*/
  PC_DDR = 0x70;
  PC_CR1 = 0x70;
  PC_CR2 = 0x70; 
/*MSB、1MHz、主设备、CPOL空闲为低、CPHA第一个时钟开始*/
  SPI_CR1 = 0x04;
/*双线单向视距传输、CRC计算禁止、软件NSS、主模式*/
  SPI_CR2 = 0x03;
/*开启SPI*/
  SPI_CR1|= 0x40;
}
void Spi_Send(u8 data)  
{
  SPI_DR = data;       //再发低八位
  while(!(SPI_SR&0x02));   //等待发送区为空
}
/*--------------------------------------------------------------*/
//写入一个字节(数据或指令)
//wbyte:<span style="white-space:pre">	</span>待写入的数据
//dat_cmd:<span style="white-space:pre">	</span>1-数据, 0-指令
void LCD_write_byte(u8 wbyte, u8 dat_cmd)
{
        LCD_CE(0);//1-数据<span style="white-space:pre">	</span>//0-指令
        LCD_DC(dat_cmd);
        Spi_Send(wbyte);
        LCD_CE(1);
}*/
/*--------------------------------------------------------------*/
//写入一个字节(数据或指令)
//wbyte:	待写入的数据
//dat_cmd:	1-数据, 0-指令
void LCD_write_byte(u8 wbyte, u8 dat_cmd)
{
	u8 i;
	
        LCD_CE(0);
//1-数据	//0-指令
        LCD_DC(dat_cmd);

	for(i = 8; i; i--)	//8位数据, 先高后低
	{
		if(wbyte & 0x80) {//LCD_DIN = 1;
                  LCD_DIN(1);}
		else		 {//LCD_DIN = 0;
                  LCD_DIN(0);}
                LCD_CLK(0);
		wbyte <<= 1;	//移位(延时)
                LCD_CLK(1);
	}
        LCD_CE(1);
}


/*--------------------------------------------------------------*/
//写入n个字节(数据)(ROM)
//*wbyte:	待写入的数据指针
//num:		待写入的数据个数
/*void LCD_write_nbyte(u8  *wbyte, u8 num)
{
	u8 i, j;
	u8 temp;

	LCD_CS = 0;			//使能
	LCD_DC = 1;			//数据

	for(j = 0; j < num; j++)//num个数据
	{
		temp = wbyte[j];
		for(i = 8; i; i--)	//8位数据, 先高后低
		{
			if(temp & 0x80) {LCD_DIN = 1;}
			else			{LCD_DIN = 0;}
		
			LCD_CLK = 0;
			temp <<= 1;		//移位(延时)
			LCD_CLK = 1;	//上升沿写入
		}	
	}
	
	LCD_CS = 1;			//禁止
}
-----------------*/

//显示清屏(清DDRAM)
void LCD_clr_scr(void)
{
	u16 i;
	
	LCD_write_cmd(X_Col_Addr);
	LCD_write_cmd(Y_Page_Addr);
	for(i = 504; i; i--) LCD_write_dat(0x00);
}


//显示清行
//num:	0 - 5
void LCD_clr_row(u8 num)
{
	u8 i;
	
	LCD_pos_byte(0, num);
	for(i = 84; i; i--) LCD_write_dat(0x00);
}


/*--------------------------------------------------------------*/
//液晶字节定位(1*1)
//液晶规划:
//x: 0 - 83
//y: 0 - 5
void LCD_pos_byte(u8 x, u8 y)
{
	x |= X_Col_Addr;  
	y |= Y_Page_Addr; 
	LCD_write_cmd(x);	//列地址
	LCD_write_cmd(y);	//页地址
}


/*--------------------------------------------------------------*/
//液晶字符输出(6*8字体)
//x: 0 - 13
//y: 0 - 5
void LCD_printc(u8 x, u8 y, u8 c_dat)
{
	u8 i;

	c_dat -= 32;		//查表
	x *= 6;				//宽6

	LCD_pos_byte(x, y);	//坐标
	for(i = 0; i < 6; i++) LCD_write_dat(Font_[c_dat][i]);	
}


/*--------------------------------------------------------------*/
//液晶字符串输出(6*8字体)
//x: 0 - 13
//y: 0 - 5
void LCD_prints(u8 x, u8 y, u8 *s_dat)
{
	while(*s_dat && x < 14) {LCD_printc(x++, y, *s_dat); s_dat++;}
}


/*--------------------------------------------------------------*/
//液晶字符串输出,自动换行(6*8字体)
//x: 0 - 13
//y: 0 - 5
void LCD_printsl(u8 x, u8 y, u8 *s_dat)
{
	while(*s_dat) 
	{
		LCD_printc(x++, y, *s_dat); 
		s_dat++;
		if(x == 14) {x = 0; y++;}
		if(y == 6)  {y = 0;}
	}
}


/*--------------------------------------------------------------*/
//液晶汉字输出(16*16字体)
//取码规则:	低位在前, 列行扫描, 阴码(1-亮, 0-灭)
//x: 0 - 4
//y: 0 - 2
void LCD_printch(u8 x, u8 y, u8  *h_dat)
{
	u8 i, j;

	x <<= 4; 	//字宽16
	y <<= 1;	//字高16
	for(j = 0; j < 2; j++)
	{
		LCD_pos_byte(x, (y + j));	//坐标
		for(i = 0; i < 16; i++) LCD_write_dat(h_dat[16 * j + i]);		
	}
}


/*--------------------------------------------------------------*/
//液晶汉字输出(16*16字体)
//查表显示输出
//取码规则:	低位在前, 列行扫描, 阴码(1-亮, 0-灭)
//x: 0 - 4
//y: 0 - 2
void LCD_showch(u8 x, u8 y, u8  *dat)
{
	u8 i;
	
	for(i = 0; i < GB_16_num; i++)
	{
		if((GB_16[i].Index[0] == dat[0]) && (GB_16[i].Index[1] == dat[1])) break;
	}
	LCD_printch(x, y, GB_16[i].Msk);
}


/*--------------------------------------------------------------*/
//液晶汉字词组输出(16*16字体)
//查表显示输出
//取码规则:	低位在前, 列行扫描, 阴码(1-亮, 0-灭)
//x: 0 - 4
//y: 0 - 2
//一行最多5个
void LCD_showsh(u8 x, u8 y, u8  *dat)
{
	while(*dat) {LCD_showch(x++, y, dat); dat += 2;}	//一个汉字GB码由2个字节组成
}


/*--------------------------------------------------------------*/
//显示84X48图片
//取码规则:	低位在前, 列行扫描, 阴码(1-亮, 0-灭)
void LCD_picture(u8  *img_dat)
{
	u16 i;

	for(i = 0; i < 504; i++) LCD_write_dat(img_dat[i]);
}


/*--------------------------------------------------------------*/
//定位显示指定大小图片
//取码规则:	低位在前, 列行扫描, 阴码(1-亮, 0-灭)
//pag:	0 - 5			页坐标
//col:  0 - 83			列坐标
//x:	0 - (83-col)	图片宽
//y:	0 - (47-pag*8)	图片高
void LCD_pos_picture(u8 col, u8 pag, u8 x, u8 y, u8  *img_dat)
{
	u8 i, j;

	y = (y + 4) >> 3;			//四舍五入
	for(j = 0; j < y; j++)
	{	
		for(i = 0; i < x; i++) 
		{
			LCD_pos_byte(col + i, pag + j);		//坐标
			LCD_write_dat(img_dat[j * x + i]);	//数据
		}
	}
}


/*--------------------------------------------------------------*/ 
//定位输出数字
//x: 0 - 13
//y: 0 - 5
//num: 0 - 65535	要显示的数字
//num_u8: 0 - 5	数字的位数
void LCD_printn(u8 x, u8 y, u16 num, u8 num_u8)
{
	signed   char i;
	u8 ii;
	u8 dat[6];
	
	for(i = 0; i < 6; i++) dat[i] = 0; 	//初始化数据
	i = 0;
	while(num / 10)						//拆位
	{
		dat[i] = num % 10;				//最低位
		num /= 10; i++;		
	}
	dat[i] = num;						//最高位
	ii = i;								//保存dat的位数
	for(; i >= 0; i--)	dat[i] += 48;	//转化成ASCII
	for(i = 0; i < num_u8; i++)
	LCD_printc(x + i, y, ' ');			//清显示区域
	for(i = ii; i >= 0; i--)
	LCD_printc(x++, y, dat[i]);			//输出数值
}


/*------------------------------------
//复位LCD5510
void LCD_reset_5510(void)
{
	LCD_clr_scr();				//清全屏
	
	LCD_write_cmd(0x25);		//省电模式, 水平寻址, 扩展指令
	LCD_write_cmd(0x04);		//VLCD温度系数0
	LCD_write_cmd(0x10);		//设置偏置系统(BSx)
	LCD_write_cmd(0xc0);		//设置电压VLCD = 3.06 + 0.06*Vop;
	
	LCD_write_cmd(0x24);		//省电模式, 水平寻址, 常规指令
	LCD_write_cmd(0x08);		//显示空白
	LCD_write_cmd(Y_Page_Addr);	//起始页地址0
	LCD_write_cmd(X_Col_Addr);	//起始列地址0
}

--------------------------*/

//初始化LCD5510
void LCD5510_Init(void)
{
	LCD_reset_hard;				//硬件复位
//	LCD_reset_soft;				//软件复位

	LCD_write_cmd(0x21);		//工作模式, 水平寻址, 扩展指令
	LCD_write_cmd(0x06);		//VLCD温度系数2
	LCD_write_cmd(0x13);		//设置偏置系统(BSx) 1:48
	LCD_write_cmd(0xc8);		//设置电压VLCD = 3.06 + 0.06*Vop, 对比度调整

	LCD_write_cmd(0x20);		//工作模式, 水平寻址, 常规指令
	LCD_write_cmd(0x0c);		//普通模式
	LCD_write_cmd(Y_Page_Addr);	//起始页地址0
	LCD_write_cmd(X_Col_Addr);	//起始列地址0
	LCD_clr_scr();				//清全屏
}
void Delay()
{
     asm("nop");
     asm("nop");
}
/*使用BEEP仅需要使用该函数*/
//频率 ≈ FLSI/8/fre    FLSI = 128KHz
void Beep_Init(void)
{
  CLK_ICKR |= 0x08;  //开启内部LSI
  while(!(CLK_ICKR&0x10)); //等待内部低速LSI就绪
  BEEP_CSR = 0x20|14;  //输出1KHz  示波器测量得出
}

u8 c8563_Store[4]={0x00,0x59,0x07,0x01};  /*写入时间初值:星期一  07:59:00*/
u8 show_time[4];
void IIC_SDA_OUT(u8 x)//PB5
{
  PB_DDR |= 0x20;
  PB_CR1 |= 0x20;
  PB_CR2 |= 0x00;
  if(x == 1)
    PB_ODR |= 0x20;
  else if(x == 0)PB_ODR &= 0xDF;
}
void IIC_SDA_IN()//PB5
{
  PB_DDR &= 0xDF;
  PB_CR1 |= 0x20; //上拉
  PB_CR2 &= 0xDF;
}
void IIC_SCL_OUT(u8 x)//PB4
{
  PB_DDR |= 0x10;
  PB_CR1 |= 0x10;
  PB_CR2 |= 0x00;
  if(x == 1)
    PB_ODR |= 0x10;
  else if(x == 0)PB_ODR &= 0xEF;
}
/****************************
I2C开始信号
****************************/
void Start()
{    
     IIC_SDA_OUT(1);
     IIC_SCL_OUT(1);
     Delay();
     IIC_SDA_OUT(0);
     Delay();
     IIC_SCL_OUT(0);
}
/**************************8
 I2C结束
 ****************************/
void Stop()
{
    IIC_SDA_OUT(0);
    IIC_SCL_OUT(0);
    Delay();
    IIC_SCL_OUT(1);
    Delay();
    IIC_SDA_OUT(1);    
}
/***********************
输出ACK=0
**************************/
void WriteACK()
{
    IIC_SDA_OUT(0);  
    Delay();
    IIC_SCL_OUT(1);
    Delay();
    IIC_SCL_OUT(0);
}
/************************
输出ACK=1
*******************/
void writenoack()
{
    IIC_SDA_OUT(1); 
    Delay();
    IIC_SCL_OUT(1);
    Delay();
    IIC_SCL_OUT(0);
}
/****************************
等待ACK
*************************/
void WaitACK()
{   u8 errtime=0;
    IIC_SDA_OUT(1); 
    Delay();               /*读ACK*/
    IIC_SCL_OUT(1);
    Delay();
    IIC_SDA_IN();
    while(PB_IDR_IDR5)
    {  errtime++;
       if(errtime==20) 
       {  
         break;
       }
    }
    IIC_SCL_OUT(0);
    Delay();
}
/***************************
输出数据一字节   
****************************/
void writebyte(u8 wdata)
{
    u8 i;
    for(i=0;i<8;i++)
    {
        if(wdata&0x80)     IIC_SDA_OUT(1); 
          else     IIC_SDA_OUT(0); 
          wdata<<=1;
          IIC_SCL_OUT(1);
          Delay();
          IIC_SCL_OUT(0);
    }
    WaitACK();
}
/***************************
 输入数据一字节  
**************************/
u8 Readbyte()
{
    u8 i,bytedata;
    IIC_SDA_OUT(1); 
    for(i=0;i<8;i++)
    {
        IIC_SCL_OUT(1);
        bytedata<<=1;
        IIC_SDA_IN();
        bytedata|=PB_IDR_IDR5;
        IIC_SCL_OUT(0);
        Delay();
    }
    return(bytedata);
}
/*******************************
 输出数据->pcf8563
********************************/
void writeData(u8 address,u8 mdata)
{
    Start();
    writebyte(0xa2);          /*写命令*/
    writebyte(address);          /*写地址*/
    writebyte(mdata);          /*写数据*/
    Stop();
}
/***********************************
输入数据<-pcf8563
***********************************/
u8 ReadData(u8 address)               /*单字节*/
{   u8 rdata;
    Start();
    writebyte(0xa2);             /*写命令*/
    writebyte(address);          /*写地址*/
    Start();
    writebyte(0xa3);             /*读命令*/
    rdata=Readbyte();
    writenoack();
    Stop();
    return(rdata);
}
/********************************
 读入时间到内部缓冲区
*********************************/
void P8563_Read()
{   u8  time[4];
    time[0] = ReadData(0x02)&0x7f; //secod
    time[1] = ReadData(0x03)&0x7f;; //minute
    time[2] = ReadData(0x04)&0x3f;; //hour
    time[3] = ReadData(0x05)&0x3f;; //day
    
    show_time[0] = (time[0]/16)*10+(time[0]%16);
    show_time[1] = (time[1]/16)*10+(time[1]%16);
    show_time[2] = (time[2]/16)*10+(time[2]%16);
    show_time[3] = (time[3]/16)*10+(time[3]%16);
}
//              sec   min hour  day
//               25    13  18   11   18:13:25
u8 set_time[4]={0x25,0x13,0x18,0x11};
/*******************
 写时间修改值
*******************/
void P8563_settime()
{
  writeData(0x02,(set_time[0]));
  writeData(0x03,(set_time[1]));
  writeData(0x04,(set_time[2]));
  writeData(0x05,(set_time[3]));
}
/****************************
 P8563的初始化 
********************************/
void P8563_init()
{
  writeData(0x00,0x20); //时钟停止
  P8563_settime();      //设置时间
  writeData(0x00,0x00); //时钟开始
}

int main( void )
{
  System_Init();
  P8563_init();
  LCD5510_Init();
  Timer4_init(0x07,0xc3); //12.5ms中断一次
//  Beep_Init();
  delay_ms(100);
  while (1)
  {
	LCD_printsl(0, 0, "1233455");
        LCD_printn(0,1,12345,6);
        P8563_Read();//读取PCF8563时钟数据
        LCD_printn(0,2,show_time[3],2);  //显示时间
        LCD_printn(3,2,show_time[2],2);  
        LCD_printn(6,2,show_time[1],2);  
        LCD_printn(9,2,show_time[0],2);  
        LCD_showsh(0, 2, "永恒之心★");
  }
}
#pragma vector=TIM4_OVR_UIF_vector  
__interrupt void TIM4_UPD_OVF_IRQHandler(void)
{
      TIM4_SR=0x00;
      i++;
      if(i==50)
      {
        LCD_BL(1);//液晶背光点亮
      }
      if(i==100)
      {
        LCD_BL(0);//液晶背光熄灭
        i=0;
      }
}

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值