본문 바로가기

컴퓨터/Cortex-M3(STM32F103)

[STM3210B]GLCD 만능달력




/************************************************
제목 :그래픽형 LCD
보드 : STM3210B
LCD : Dr.Kim GRAPHIC LCD Module MLCD-200
최초작성일 : 2011.06.28
작성자 : 부산직업능력개발원 정보기술 ***

핀연결
1(DB5) : PA5
2(DB4) : PA4
3(DB6) : PA6
4(DB3) : PA3
5(DB7) : PA7
6(DB2) : PA2
8(DB1) : PA1
10(DB0) : PA0
11(E)  : PE7
13(RS)  : PE9
15(/CS2) : PE11
17(/CS1) : PE13
19(VCC) : 5V
20(GND) : GND
*************************************************/
#include "stm32f10x.h"
#include "font.h"
#include "e_font5x7.h"
#include "txt_128x64.h"
#include <time.h>
#include <stdio.h>
#include <string.h>

#define READ_UP   ((GPIOD->IDR & GPIO_Pin_8)==0)
#define READ_DOWN  ((GPIOD->IDR & GPIO_Pin_14)==0)
#define READ_LEFT  ((GPIOE->IDR & GPIO_Pin_1)==0)
#define READ_RIGHT  ((GPIOE->IDR & GPIO_Pin_0)==0)
#define READ_SET  ((GPIOD->IDR & GPIO_Pin_12)==0)

#define LCD_CTRL GPIOE->ODR
#define LCD_DATA GPIOA->ODR

#define LCD_E GPIO_Pin_7 //e
#define LCD_RS GPIO_Pin_9 //e
#define LCD_CS2 GPIO_Pin_11 //e
#define LCD_CS1 GPIO_Pin_13 //e

void lcdg(void);
void lcdc(u8 ctrl);
void lcdd(u8 se, u8 _data);
void String(char *);
void lcdr(u8 x,u8 y,u8 *string);
void delay(u32 d1, u32 d2);
void RTC_Config(void);
void timeset(s32 t){
 RTC_Config();
 RTC_WaitForLastTask();
 RTC_SetCounter(t);
 RTC_WaitForLastTask();
}

void fill_screen(char c){ //화면전체 체움
 u8 i,j;
 for(j=0;j<8;j++) {
  //set page
  lcdc(0xb8+j);
  for(i=0;i<64;i++){
   //set y addr.
   lcdc(0x40+i);
   lcdd(1,c); //left lcd
  }
 }
 for(j=0;j<8;j++) {
  //set page
  lcdc(0xb8+j);
  for(i=0;i<64;i++){
   //set y addr.
   lcdc(0x40+i);
   lcdd(2,c);  //right lcd
  }
 }
}

void fill_byte_screen(u8 x, u8 y, u8 c) {//1byte 채움
 u8 lcd;
 
 if(y>=64) lcd=2;
 else lcd=1;
 y = y % 64;
 
 //set page
 lcdc(0xb8+x);
 //set y addr.
 lcdc(0x40+y);
 lcdd(lcd,c); //left or right
}
 
void fill_eng(u8 x, u8 y, char c) { //1글자 채움
 u8 i;
 for(i=0;i<5;i++) {
  fill_byte_screen(x, y+i, font5x7[(c-' ')*5+i]);
 }
}

void fill_eng_inv(u8 x, u8 y, char c) { //1글자 역상으로 채움
 u8 i;
 for(i=0;i<5;i++) {
  fill_byte_screen(x, y+i, ~font5x7[(c-' ')*5+i]);
 }
}

void fill_dd(u8 x, u8 y) { //요일출력
 u8 i;
 for(i=0;i<112;i++) {
  fill_byte_screen(x, y+i, ~(TextFontTbl[i]));
  fill_byte_screen(x+1, y+i, ~(TextFontTbl[112+i]));
 }
}

void makecal(u16 year, u8 month, u8 day, u8 yoilstart, u8 dayend)
{
 char temp[3],px,py;
 fill_dd(0,8);    //요일출력
 px=2; py=10;
 for(u8 i=0;i<yoilstart;i++) { //공백으로 채우기.
  fill_eng(px,py,' ');
  fill_eng(px,py+5,' ');
  py += 16;
 }
 
 px=2; py=10+yoilstart*16;
 for(u8 j=1;j<=37;j++){
  sprintf(temp,"%2d",j);
  if(j>dayend) {//공백채우기
   fill_eng(px,py,' ');
   fill_eng(px,py+5,' ');
  }
  else if(j==day) {//역상으로 채우기
   fill_eng_inv(px,py,temp[0]);
   fill_eng_inv(px,py+5,temp[1]);
  }
  else { //정상적으로 숫자 채우기..
   fill_eng(px,py,temp[0]);
   fill_eng(px,py+5,temp[1]);
  }
  py += 16;
  if((j+yoilstart)%7==0) {
   px++;
   py=10;
  }
  if(px==7 && py==(10+16+16+16)) break;
 }
}

int main(void){
 
 GPIO_InitTypeDef GPIO;
 
 char temp[10];
 u8 m2[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
 
 
 u8 upkey,downkey,leftkey,rightkey,setkey;
 u8 pupkey,pdownkey,pleftkey,prightkey,psetkey;
 u32 loop,tmp;
 u8 blink=0;
  
 u8 h,m,s,mm,dd; //초기값
 u8 wd1,dispmm,wd2;
 u16 yy,dispyy;
 
 u32 timevar;
 //char temp[16];
 enum {normal, setyear, setmonth, setday, sethour, setmin, setsec, caldisp} mode=normal;
 struct tm *now;
 
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOD,ENABLE);
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP|RCC_APB1Periph_PWR,ENABLE);
 
 GPIO.GPIO_Mode=GPIO_Mode_Out_PP;
 GPIO.GPIO_Speed=GPIO_Speed_2MHz;
 GPIO.GPIO_Pin=0xff;
 GPIO_Init(GPIOA, &GPIO);
 
 GPIO.GPIO_Pin=GPIO_Pin_7|GPIO_Pin_9|GPIO_Pin_11|GPIO_Pin_13;
 GPIO_Init(GPIOE, &GPIO);
 
 GPIO.GPIO_Mode=GPIO_Mode_IN_FLOATING; //입력/ 조이스틱
 GPIO.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_14|GPIO_Pin_12;
 GPIO_Init(GPIOD, &GPIO);
 
 GPIO.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
 GPIO_Init(GPIOE, &GPIO);
 
 LCD_CTRL &= ~(GPIO_Pin_7|GPIO_Pin_9|GPIO_Pin_11|GPIO_Pin_13);
 LCD_DATA &= ~(0xff);
 
 delay(30,100);
 
 lcdg(); //초기화
 
 
 
 while(1){
  //px=7; py=80;
  //시계 
  loop++;
  if(loop>0){
   loop=0;
   blink= ~blink;
  }
  timevar=RTC_GetCounter();
  now=localtime(&timevar);
  yy=now->tm_year+2000;
  mm=now->tm_mon+1;
  dd=now->tm_mday;
  h=now->tm_hour;
  m=now->tm_min;
  s=now->tm_sec;
  
  m2[2]=28; //초기화 필요.
  if(yy % 4 == 0) m2[2]=29;
  if(yy % 100 == 0) m2[2]=28;
  if(yy % 400 == 0) m2[2]=29;
  
  tmp = 0;
  tmp += (yy-1); //전년도까지 년수
  tmp += ((yy-1)/4);
  tmp -= ((yy-1)/100);
  tmp += ((yy-1)/400);
  for(u8 i=0;i<mm;i++) tmp += m2[i]; //전월까지 일수
  
  wd1 = (tmp+1) % 7; //1일자 요일
  
    
  
  setkey = READ_SET;
  upkey = READ_UP;
  downkey = READ_DOWN;
  leftkey = READ_LEFT;
  rightkey = READ_RIGHT;
  
  switch(mode) {
  case normal:  //현재실시간모드
   if((upkey != pupkey) && upkey){
    dispyy = yy+1;
    dispmm = mm;
    mode=caldisp;
   }
   if((downkey != pdownkey) && downkey){
    dispyy = yy-1;
    dispmm = mm;
    mode=caldisp;
   }
   if((leftkey != pleftkey) && leftkey){
    dispmm = mm-1;
    dispyy = yy;
    mode=caldisp;
   }
   if((rightkey != prightkey) && rightkey){
    dispmm = mm+1;
    dispyy = yy;
    mode=caldisp;
   }
   if((setkey != psetkey) && setkey){
    mode = setyear;
   }  
   makecal(yy,mm,dd,wd1,m2[mm]);
   sprintf(temp,"%4d",yy);
   fill_eng(7,40,temp[0]);
   fill_eng(7,45,temp[1]);
   fill_eng(7,50,temp[2]);
   fill_eng(7,55,temp[3]);
   fill_eng(7,60,'/');
   sprintf(temp,"%2d",mm);
   fill_eng(7,65,temp[0]);
   fill_eng(7,70,temp[1]);
   sprintf(temp,"%2d:%02d:%02d",h,m,s);
   for(u8 i=0;i<8;i++) fill_eng(7,78+5*i,temp[i]);
   break;
  case setyear:  //년 모드
   if((upkey != pupkey) && upkey){
    now->tm_year+=1;
    timeset(mktime(now));
   }
   if((downkey != pdownkey) && downkey){
    now->tm_year-=1;
    timeset(mktime(now));
   }
   if((rightkey != prightkey) && rightkey){
    mode = setmonth;
   }
   if((setkey != psetkey) && setkey){
    mode = normal;
   }
 
   makecal(yy,mm,dd,wd1,m2[mm]);
   sprintf(temp,"%4d",yy);
   if(blink) {
    fill_eng_inv(7,40,temp[0]);
    fill_eng_inv(7,45,temp[1]);
    fill_eng_inv(7,50,temp[2]);
    fill_eng_inv(7,55,temp[3]);
   }
   else {
    fill_eng(7,40,temp[0]);
    fill_eng(7,45,temp[1]);
    fill_eng(7,50,temp[2]);
    fill_eng(7,55,temp[3]);
   }
   fill_eng(7,60,'/');
   sprintf(temp,"%2d",mm);
   fill_eng(7,65,temp[0]);
   fill_eng(7,70,temp[1]);
   sprintf(temp,"%2d:%02d:%02d",h,m,s);
   for(u8 i=0;i<8;i++) fill_eng(7,78+5*i,temp[i]);
   break;
  case setmonth:  //월 모드
   if((upkey != pupkey) && upkey){
    now->tm_mon+=1;
    timeset(mktime(now));
   }
   if((downkey != pdownkey) && downkey){
    now->tm_mon-=1;
    timeset(mktime(now));
   }
   if((leftkey != pleftkey) && leftkey){
    mode = setyear;
   }
   if((rightkey != prightkey) && rightkey){
    mode = setday;
   }
   if((setkey != psetkey) && setkey){
    mode = normal;
   }
   makecal(yy,mm,dd,wd1,m2[mm]);
   sprintf(temp,"%4d",yy);
   fill_eng(7,40,temp[0]);
   fill_eng(7,45,temp[1]);
   fill_eng(7,50,temp[2]);
   fill_eng(7,55,temp[3]);
   fill_eng(7,60,'/');
   sprintf(temp,"%2d",mm);
   if(blink){
    fill_eng_inv(7,65,temp[0]);
    fill_eng_inv(7,70,temp[1]);
   }
   else{
    fill_eng(7,65,temp[0]);
    fill_eng(7,70,temp[1]);
   }
   sprintf(temp,"%2d:%02d:%02d",h,m,s);
   for(u8 i=0;i<8;i++) fill_eng(7,78+5*i,temp[i]);
   break;
  case setday:  //일 모드
   if((upkey != pupkey) && upkey){
    now->tm_mday+=1;
    timeset(mktime(now));
   }
   if((downkey != pdownkey) && downkey){
    now->tm_mday-=1;
    timeset(mktime(now));
   }
   if((leftkey != pleftkey) && leftkey){
    mode = setmonth;
   }
   if((rightkey != prightkey) && rightkey){
    mode = sethour;
   }
   if((setkey != psetkey) && setkey){
    mode = normal;
   }
   makecal(yy,mm,dd,wd1,m2[mm]);
   sprintf(temp,"%4d",yy);
   fill_eng(7,40,temp[0]);
   fill_eng(7,45,temp[1]);
   fill_eng(7,50,temp[2]);
   fill_eng(7,55,temp[3]);
   fill_eng(7,60,'/');
   sprintf(temp,"%2d",mm);
   fill_eng(7,65,temp[0]);
   fill_eng(7,70,temp[1]);
   sprintf(temp,"%2d:%02d:%02d",h,m,s);
   for(u8 i=0;i<8;i++) fill_eng(7,78+5*i,temp[i]);
   break;
  case sethour:   //시간을설정하는 모드
   if((upkey != pupkey) && upkey){
    now->tm_hour+=1;
    timeset(mktime(now));
   }
   if((downkey != pdownkey) && downkey){
    now->tm_hour-=1;
    timeset(mktime(now));
   }
   if((leftkey != pleftkey) && leftkey){
    mode = setday;
   }
   if((rightkey != prightkey) && rightkey){
    mode = setmin;
   }
   if((setkey != psetkey) && setkey){
    mode = normal;
   }
   if(blink==0) sprintf(temp,"%02d:  :  ",h);
   else sprintf(temp,"%2d:%02d:%02d",h,m,s);
   for(u8 i=0;i<8;i++) fill_eng(7,78+5*i,temp[i]);
   break;
  case setmin:  //분 모드
   if((upkey != pupkey) && upkey){
    now->tm_min+=1;
    timeset(mktime(now));
   }
   if((downkey != pdownkey) && downkey){
    now->tm_min-=1;
    timeset(mktime(now));
   }
   if((leftkey != pleftkey) && leftkey){
    mode = sethour;
   }
   if((rightkey != prightkey) && rightkey){
    mode = setsec;
   }
   if((setkey != psetkey) && setkey){
    mode = normal;
   }
   if(blink==0) sprintf(temp,"  :%02d:  ",m);
   else sprintf(temp,"%2d:%02d:%02d",h,m,s);
   for(u8 i=0;i<8;i++) fill_eng(7,78+5*i,temp[i]);
   break;
  case setsec:  //초 모드
   if((upkey != pupkey) && upkey){
    now->tm_sec+=1;
    timeset(mktime(now));
   }
   if((downkey != pdownkey) && downkey){
    now->tm_sec-=1;
    timeset(mktime(now));
   }
   if((leftkey != pleftkey) && leftkey){
    mode = setmin;
   }
   if((setkey != psetkey) && setkey){
    mode = normal;
   }
   if(blink==0) sprintf(temp,"  :  :%02d",s);
   else sprintf(temp,"%2d:%02d:%02d",h,m,s);
   for(u8 i=0;i<8;i++) fill_eng(7,78+5*i,temp[i]);
   break;
  case caldisp:
   if((upkey != pupkey) && upkey){
    dispyy++;
   }
   if((downkey != pdownkey) && downkey){
    dispyy--;
   }
   if((leftkey != pleftkey) && leftkey){
    dispmm--;
    if(dispmm==0) {
     dispmm=12;
     dispyy--;
    }
   }
   if((rightkey != prightkey) && rightkey){
    dispmm++;
    if(dispmm==13) {
     dispmm=1;
     dispyy++;
    }
   }
   if((setkey != psetkey) && setkey){
    mode = normal;
   }
   m2[2]=28; //초기화 필요.
   if(dispyy % 4 == 0) m2[2]=29;
   if(dispyy % 100 == 0) m2[2]=28;
   if(dispyy % 400 == 0) m2[2]=29;
   
   tmp = 0;
   tmp += (dispyy-1); //전년도까지 년수
   tmp += ((dispyy-1)/4);
   tmp -= ((dispyy-1)/100);
   tmp += ((dispyy-1)/400);
   for(u8 i=0;i<dispmm;i++) tmp += m2[i]; //전월까지 일수
   for(u8 i=40;i<=70;i++) fill_eng(7,i,' ');
   wd2 = (tmp+1) % 7; //1일자 요일
   makecal(dispyy,dispmm,0,wd2,m2[dispmm]);
   sprintf(temp,"%4d/%02d/",dispyy,dispmm);
   for(u8 i=0;i<8;i++) fill_eng(7,78+5*i,temp[i]);
   break;
  }
  
  pupkey = upkey;
  pdownkey = downkey;
  pleftkey = leftkey;
  prightkey = rightkey;
  psetkey = setkey;
  
  }
}

void String(char *string){
 while(*string != '\0'){
  //lcdd(*string);
  string++;
 }
}

 

void lcdr(u8 x, u8 y, u8 *string){
 u8 i,a,y_aes;
 if(y<=7){
  a=1;
  y_aes=y*8;
 }
 else {
  a=2;
  y_aes=(y-8)*8;
 }
 lcdc(0xb8+x*2);
 lcdc(0x40+y_aes);
 for(i=0;i<=15;i++){
  lcdd(a,*string);
  string++;
 }
 lcdc(0xb8+x*2+1);
 lcdc(0x40+y_aes);
 for(i=0;i<=15;i++){
  lcdd(a,*string);
  string++;
 }
}

void lcdg(void){
 u8 i,j,x,y;
 
 lcdc(0x3f);
 lcdc(0xc0);
 x=0xb8;
 y=0x40;
 for(i=0;i<8;i++){
  lcdc(x);
  lcdc(y);
  for(j=0;j<64;j++) lcdd(0,0);
  x++;
 }
}

void lcdc(u8 ctrl){
 LCD_CTRL |= LCD_E;
 delay(10,1);
 LCD_DATA &= ~0xff;
 LCD_DATA |= ctrl;
 delay(10,1);
 LCD_CTRL &= ~(GPIO_Pin_7|GPIO_Pin_9|GPIO_Pin_11|GPIO_Pin_13);
 delay(100,10);
}

void lcdd(u8 se, u8 _data){
 switch(se){
 case 0:
  LCD_CTRL |= LCD_E|LCD_RS;
  LCD_CTRL &= ~(LCD_CS2|LCD_CS1);
  delay(10,1);
  LCD_DATA &= ~0xff;
  LCD_DATA |= _data;
  delay(10,1);
  LCD_CTRL &= ~(GPIO_Pin_7|GPIO_Pin_9|GPIO_Pin_11|GPIO_Pin_13);
  break;
 case 1:
  LCD_CTRL |= LCD_E|LCD_RS|LCD_CS2;
  LCD_CTRL &= ~(LCD_CS1);
  delay(10,1);
  LCD_DATA &= ~0xff;
  LCD_DATA |= _data;
  delay(10,1);
  LCD_CTRL &= ~(GPIO_Pin_7|GPIO_Pin_9|GPIO_Pin_11|GPIO_Pin_13);
  break;
 case 2:
  LCD_CTRL |= LCD_E|LCD_RS|LCD_CS1;
  LCD_CTRL &= ~(LCD_CS2);
  delay(10,1);
  LCD_DATA &= ~0xff;
  LCD_DATA |= _data;
  delay(10,1);
  LCD_CTRL &= ~(GPIO_Pin_7|GPIO_Pin_9|GPIO_Pin_11|GPIO_Pin_13);
  break;
 }
 delay(100,10);
}

void delay(u32 d1, u32 d2){
 vu32 i,j;
 for(i=0;i<d1;i++) for(j=0;j<d2;j++);
}

void RTC_Config(void){
 PWR_BackupAccessCmd(ENABLE);
 RCC_LSEConfig(RCC_LSE_ON);
 while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET);
 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
 RCC_RTCCLKCmd(ENABLE);
 RTC_WaitForLastTask();
 RTC_SetPrescaler(32767);
 RTC_WaitForSynchro();
 RTC_WaitForLastTask();
 RTC_ITConfig(RTC_IT_SEC,ENABLE);
 RTC_WaitForLastTask();
}