카테고리 없음

[AVR] Door Lock 관련 Atmega128 Code 내용

도영수 2015. 10. 2. 12:39

이전에 대학교 때, 작성한 도어락 과제입니다.


기능들은 한 기판에 3개의 기능을 구현하기 위해서 상태 변수를 이용해서 순차적으로  이동 시키면서 모드를 결정할 수 있도록 하였습니다.


조금 난잡할지도 모르지만, 도움이 필요하신 분들은 참고하세요 ~

 

기능은 : adc 측정, 도어락, 계산기, 블루투스(RS-232통신), EEPROM 이용, Stepping Motor Control입니다.

 

소스 - 

 

 #include <avr/io.h>

#include <util/delay.h>

#include <avr/interrupt.h>

 

 

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

//    A

//  F   B

//    G

//  E   C

//    D

//   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   A,   b,   C,   d,   E,   F

unsigned char font_data[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};

unsigned char ucKeyValue = 0;

unsigned int uiDelayCnt = 0;

unsigned char uc1msCnt = 0;

unsigned char uc100msCnt = 0;

unsigned char ucKeyIn_2 = 0;

unsigned char ucKeyCnt = 0;

unsigned char ucDisp = 0;

 

 

 

unsigned char  ucRs232Data_t; // uart 수신 데이터

unsigned char   ucRs232Data_r; // uart 송신 데이터

unsigned int uartToggle = 0; // uart on/off

 

unsigned int  timer_count = 0;

unsigned int flag= 1;

 

unsigned int calculator_f = 0;

unsigned int calculator_s = 0;

unsigned char calculator_o;

unsigned int calculator_q = 1;

 

unsigned char ucI2Cd = 0;

unsigned char ucPreKey = 0;

 

//#define DISPLAY_HEX

 

#define OPER_LED 0x20

#define OK_LED 0x10

#define ERROR_LED 0x08

#define MOTOR 0x04

 

#define DIGIT0 0x80

#define DIGIT1 0x40

 

#define SCL 0x01

#define SDA 0x02

#define WC 0x04

 

#define _RDMODE   DDRD &= ~SDA // SDA input

#define _WRMODE   DDRD |= SDA  // SDA output

#define I2C_WCMD  0xA0

#define I2C_RCMD  0xA1

 

#define _KEY_0 0

#define _KEY_1 1

#define _KEY_2 2

#define _KEY_3 3

#define _KEY_4 4

#define _KEY_5 5

#define _KEY_6 6

#define _KEY_7 7

#define _KEY_8 8

#define _KEY_9 9

#define _KEY_F2 10

#define _KEY_OPEN 11

#define _KEY_CLOSE 12

#define _KEY_SET 13

#define _KEY_CLEAR 14

#define _KEY_F1 15

 

#define _DOORLOOK_LED 0x01

#define _ADC_DIS_LED 0x02

#define _CALCULATOR_LED 0x04

#define _UART_LED 0x08

 

#define SYSTEM_CLOCK 8000000 //mcu clock

union{

unsigned char flag;

struct{

unsigned F_OPER_LED : 1;

unsigned F_key_chg : 1;

unsigned F_OpenCheck : 1;

unsigned F_CloseCheck : 1;

unsigned    int F_Mode : 1;

}M_S;

}M_U;

 

#define Mbit M_U.M_S

unsigned int uartCount = 0;

 

 

 

void Display(unsigned char ucDispValue);

 

void key_check(void);

 

void EEPROM_RESET(void);

void EEPROM_START(void);

void EEPROM_STOP(void);

unsigned char EEPROM_READ_8b(void);

unsigned char  EEPROM_WRITE_8b(unsigned char d);

unsigned char EEPLOAD_1BYTE(unsigned char address);

void  EEPSAVE_1BYTE(unsigned char addr, unsigned char data);\

 

void  SERVOR_Motor(int angle);

 

void  rs232Init(unsigned long BaudRate);

void  unRs232Init();

unsigned char  RX1_char_scan(void);

void  TX1_char(unsigned char data);

 

int  ADC_init();

unsigned int  ADC_Load();

 

 

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

  7 segment Display routine - 2 digit 7 segment dynamic display

Display data: ucDispValue

Display Result data: font_data

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

void Display(unsigned char ucDispValue)

{

unsigned char ucDigit1, ucDigit2;

 

#ifdef DISPLAY_HEX

ucDigit1 = ucDispValue / 16;

ucDigit2 = ucDispValue % 16;

#else

ucDigit1 = ucDispValue / 10;

ucDigit2 = ucDispValue % 10;

#endif

 

PORTA = font_data[ucDigit1];

PORTF &= ~DIGIT0;

PORTF |= DIGIT1;

_delay_ms(10);

 

PORTA = font_data[ucDigit2];

PORTF &= ~DIGIT1;

PORTF |= DIGIT0;

_delay_ms(10);

}

 

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

  EPPROM

  

  

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

 

void EEPROM_RESET(void)

{  

char i; 

 

    DDRD |= SDA; // SDA Output

    _delay_us(3);

    PORTD |= SDA; // SDA High

    PORTD &= ~SCL; // SDL Low

    _delay_us(3);

 

    for(i=0;i<9;i++) // 9 SCK cycles

   

       PORTD |= SCL; // SCL High

       _delay_us(3);

       PORTD &= ~SCL; // SCL Low

       _delay_us(3);

    }

}

 

 

void EEPROM_START(void)

{

PORTD |= SCL;

PORTD |= SDA;

PORTD |= SCL;

PORTD &= ~SDA;

PORTD &= ~SCL;

}

 

 

void EEPROM_STOP(void)

{

PORTD &= ~SCL;

PORTD &= ~SDA;

PORTD |= SCL;

PORTD |= SDA;

}

 

 

unsigned char EEPROM_READ_8b(void)

{

unsigned char i = 0;

unsigned char d = 0;

 

DDRD &= ~SDA; // SDA Input

_delay_us(2);

    for(i=8; i; i--)

    {

       d <<= 1;

PORTD |= SCL;

       if(PIND & SDA) d++;

PORTD &= ~SCL;

    }

DDRD |= SDA; // SDA Output

    return(d);

}

 

 

unsigned char EEPROM_WRITE_8b(unsigned char d)

{  

unsigned char i;

 

    for (i=8; i; i--){

if(d & 0x80) PORTD |= SDA; // SDA High

       else PORTD &= ~SDA; // SDA Low

PORTD |= SCL;

PORTD &= ~SCL;

       d <<= 1;

    }

DDRD &= ~SDA; // SDA Input

PORTD |= SCL;

 

_delay_ms(5);

 

if(PIND & SDA) i = 1;

else i = 0;

DDRD |= SDA;

PORTD &= ~SDA;

PORTD &= ~SCL;

    return(i);

}

 

 

unsigned char EEPLOAD_1BYTE(unsigned char address)

{

unsigned char data;

 

 

EEPROM_STOP();

EEPROM_START();

 

if(EEPROM_WRITE_8b(I2C_WCMD)) return(0); // write cmd set

if(EEPROM_WRITE_8b(address)) return(0); // WORD ADDRESS n

EEPROM_STOP();

 

EEPROM_START();

if(EEPROM_WRITE_8b(I2C_RCMD)) return(0); // read cmd set

 

data = EEPROM_READ_8b(); // DATA

 

PORTD |= SDA;

PORTD |= SCL;

PORTD &= ~SCL;

 

EEPROM_STOP(); // STOP

PORTD |= SDA;

PORTD |= SCL;

 

return(data);

}

 

void EEPSAVE_1BYTE(unsigned char addr, unsigned char data)

{

EEPROM_STOP();

EEPROM_START();

 

while(EEPROM_WRITE_8b(I2C_WCMD))

_delay_ms(5);

while(EEPROM_WRITE_8b(addr))

_delay_ms(5);

while(EEPROM_WRITE_8b(data))

_delay_ms(5);

EEPROM_STOP();

PORTD |= SDA;

PORTD |= SCL;

}

 

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

  servor 

  

  

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

 

 

void SERVOR_Motor(int angle){ // angle : -90도 ~ +90도

unsigned int i=0;

switch(angle)

{

case -90 :

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

{

PORTF |= MOTOR;             

_delay_us(650);                

PORTF &= ~MOTOR;             

_delay_us(23000-650);

}     

break;

 

case 0 :

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

{

PORTF |= MOTOR;

_delay_us(1500);

PORTF &= ~MOTOR;

_delay_us(23000-1500);

}

break;

}

}

 

 

// 초기화 

 

void rs232Init(unsigned long BaudRate)

{

  UBRR1H = 0;                                   

  UBRR1L = SYSTEM_CLOCK/BaudRate/16 - 1;

  UCSR1A = 0x00;                              

  UCSR1B = 0x18;                                

  UCSR1C = 0x06; 

}

 

void unRs232Init()

{

  UBRR1H = 0x00;                                   

  UBRR1L = 0x00;

  UCSR1A = 0x00;                              

  UCSR1B = 0x00;                             

  UCSR1C = 0x00; 

}

 

// 송신

unsigned char RX1_char_scan(void)

{

  if((UCSR1A & 0x80) == 0x00)   

    return 0x00;                               

  else                                          

    return UDR1;                               

}

// 수신

void TX1_char(unsigned char data)

{

  while((UCSR1A & 0x20) == 0x00);

  UDR1 = data;

}

 

 

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

  4 X 4 matrix key check routine

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

void key_check()

{

unsigned char ucKeyInBuf0, ucKeyInBuf1, ucKeyInBuf2, ucKeyInBuf3;

unsigned char ucKeyIn0, ucKeyIn1, ucKeyIn2, ucKeyIn3;

unsigned char ucPreKeyBuf = 0;

unsigned char ucKeyIn = 0;

 

ucKeyIn0 = 0;

ucKeyIn1 = 0;

ucKeyIn2 = 0;

ucKeyIn3 = 0;

 

PORTC = 0x70;

_delay_us(10);

ucKeyInBuf0 = PINC & 0x0F;

if(ucKeyInBuf0 < 0x0F) ucKeyIn0 = PINC & 0x1F;

 

PORTC = 0xB0;

_delay_us(10);

ucKeyInBuf1 = PINC & 0x0F;

if(ucKeyInBuf1 < 0x0F) ucKeyIn1 = PINC & 0x2F;

 

PORTC = 0xD0;

_delay_us(10);

ucKeyInBuf2 = PINC & 0x0F;

if(ucKeyInBuf2 < 0x0F) ucKeyIn2 = PINC & 0x4F;

 

PORTC = 0xE0;

_delay_us(10);

ucKeyInBuf3 = PINC & 0x0F;

if(ucKeyInBuf3 < 0x0F) ucKeyIn3 = PINC & 0x8F;

 

ucKeyIn = (ucKeyIn0 | ucKeyIn1 | ucKeyIn2 | ucKeyIn3);

 

if(ucKeyIn >= 0x17){

ucKeyCnt++;

}

else ucKeyCnt = 0;

 

if(ucKeyCnt >= 10){

ucKeyCnt = 0;

Mbit.F_key_chg = 1;

}

 

if(ucKeyIn == 0x00){

TIMSK = 0x00;

}

else{

TIMSK = 0x01;

ucKeyIn_2 = ucKeyIn;

}

switch(ucKeyIn){

case 0x1E:

ucRs232Data_t = _KEY_1;

ucKeyValue = _KEY_1;

break;

case 0x1D:

ucKeyValue = _KEY_4;

ucRs232Data_t = _KEY_4;

break;

case 0x1B:

ucKeyValue = _KEY_7;

ucRs232Data_t = _KEY_7;

break;

case 0x17:

ucKeyValue = _KEY_0;

ucRs232Data_t = _KEY_0;

break;

case 0x2E:

ucKeyValue = _KEY_2;

ucRs232Data_t = _KEY_2;

break;

case 0x2D:

ucKeyValue = _KEY_5;

ucRs232Data_t = _KEY_5;

break;

 

case 0x2B :

ucKeyValue = _KEY_8;

ucRs232Data_t = _KEY_8;

break;

 

case 0x4E:

ucKeyValue = _KEY_3;

ucRs232Data_t = _KEY_3;

break;

case 0x4D:

ucKeyValue = _KEY_6;

ucRs232Data_t = _KEY_6;

break;

case 0x4B:

ucKeyValue = _KEY_9;

ucRs232Data_t = _KEY_9;

break;

case 0x87: // F2 - uart operation

switch(flag){

case 1 :

break;

case 2 :

break;

case 3 :

break;

}

break;

}

}

 

// ADC 초기화

 

int ADC_init()

{

ADCSRA = 0xE7;

ADMUX = 0xC0;

ADC = 0x00; //ADC Value Save Register (ADCW = Analolg Digital Convert Word = ADCH+ADC)

}

 

unsigned int ADC_Load()

{

unsigned int adc_data;

adc_data = ADC;

adc_data = adc_data - 90;

return adc_data;

}

/*

#define NORMAL_MODE 0x41

#define CLOCK_1 0x01

#define CLOCK_8 0x02

#define CLCOK_128 0x05

#define TIMER_MATCH_E 0x40

 

void timer2_init(){

TCCR2 |= NORMAL_MODE;

TCCR2 |= CLCOK_128;

TCNT2 = 0;

TIMSK |= TIMER_MATCH_E;

}

*/

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

  Timer0 ISR

 

 t = 분주비 * (256 - TCNT0 초기값) / 8000000

   = 32 * (256 - TCNT0) / 8000000

   = 1ms(when TCNT0 = 6)

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

ISR(TIMER0_OVF_vect)

{

uc1msCnt++;

if(uc1msCnt >= 100){

uc1msCnt = 0;

uc100msCnt++;

Mbit.F_OPER_LED = 1;

if(uc100msCnt >= 10){

uc100msCnt = 0;

}

}

if(timer_count >= 425){

if(ucKeyIn_2 == 0x8B){  // Mode select

TX1_char(flag);

flag++;

if(flag == 4) flag = 1;

}

if(ucKeyIn_2 == 0x87){ // uart toggle

if(uartToggle ==0){

uartToggle = 1;

}

else

{

uartToggle = 0;

}

}

if(ucRs232Data_t != 0x00){ // data TX

TX1_char(ucRs232Data_t);

ucRs232Data_t = 0;

uartCount=0;

}

if(ucKeyIn_2 == 0x8E){ // set // X  // + 연산

switch(flag){

case 1 :

unRs232Init();

EEPSAVE_1BYTE(1,ucDisp); // Write function from ucDisp to EEPROM

break;

case 2 :

break;

case 3 :

calculator_o = '+';

if(calculator_q == 1){

calculator_f = ucDisp;

calculator_q = 2;

v_clear();

}

else {

calculator_s = ucDisp;

v_clear();

calculator_result();

}

break;

}

}

if(ucKeyIn_2 == 0x8D){ // EPPROM RAED // X // - 연산

switch(flag){

case 1 :

v_clear();

ucDisp = EEPLOAD_1BYTE(1);

break;

case 2 :

break;

case 3 :

calculator_o = '-';

if(calculator_q == 1){

calculator_f = ucDisp;

calculator_q = 2;

v_clear();

}

else{

calculator_s = ucDisp;

v_clear();

calculator_result();

}

break;

}

}

if(ucKeyIn_2 == 0x27){ // open //  x // =

switch(flag){

case 1 :

Mbit.F_OpenCheck = 1;

break;

case 2 :

break;

case 3 :

calculator_s = ucDisp;

v_clear();

calculator_result();

break;

}

}

if(ucKeyIn_2 == 0x47){ // close // X //  C(reset)

switch(flag){

case 1 :

Mbit.F_CloseCheck = 1;

break;

case 2 :

break;

case 3 :

calculator_f = 0;

calculator_o = 0;

calculator_q = 1;

calculator_s = 0;

v_clear();

break;

}

}

timer_count = 0;

TIMSK = 0x00;

}

uartCount++;

timer_count++;

}

 

void calculator_result(){

unsigned int result =0;

switch(calculator_o){

case '+' :

result = calculator_f + calculator_s;

break;

case '-' :

result = calculator_f - calculator_s;

break;

}

calculator_q = 1;

if(result >= 99){

ucDisp = 99;

}

else if(result < 1 ){

ucDisp = 0;

}

ucDisp = result;

}

 

unsigned int charIntDataFilter (unsigned char num)

{

unsigned int uartResult = 0;

switch(num){

case '1' :

uartResult = 1;

break;

case '2' :

uartResult = 2;

break;

case '3' :

uartResult = 3;

break;

case '4' :

uartResult = 4;

break;

case '5' :

uartResult = 5;

break;

case '6' :

uartResult = 6;

break;

case '7' :

uartResult = 7;

break;

case '8' :

uartResult = 8;

break;

case '9' :

uartResult = 9;

break;

case '0' :

uartResult = 0;

break;

case 'a' :

uartResult = 11;

break;

case 'b' :

uartResult = 12;

break;

case 'c' :

uartResult = 13;

break;

case 'd' :

uartResult = 14;

break;

case 'e' :

uartResult = 15;

break;

case 'f' :

uartResult = 16;

break;

case 'g' :

uartResult = 17;

break;

case 'h' :

uartResult = 18;

break;

case 'i' :

uartResult = 19;

break;

case 'j' :

uartResult = 20;

break;

default:

uartResult = 21;

break;

}

return uartResult;

}

 

unsigned char intCharfilter (unsigned int num){

unsigned char result;

if(num == 1) result = 0x01;

if(num == 2) result = 0x02;

if(num == 3) result = 0x03;

if(num == 4) result = 0x04;

if(num == 5) result = 0x05;

if(num == 6) result = 0x06;

if(num == 7) result = 0x07;

if(num == 8) result = 0x08;

if(num == 9) result = 0x09;

if(num == 0) result = 0x00;

return result;

}

 

void v_clear (){ 

ucDisp = 0;

ucKeyValue = 0;

ucPreKey = 0;

}

 

 

int main()

{

unsigned int flag3_S = 1; // 3번(계산기) 상태로 들어 왔을 때 초기화 하기 위해서 사용

int uart_onOFF=0; // uart 초기화를 한번만 하기 위해서 사용

 

TWBR = 12;

TWSR = 0x00;

 

SREG = 0x80;

 

DDRA = 0xFF; // 0-7: segment output

DDRC = 0xF0; // 0-3: key in, 4-7: scan output

DDRD = 0x07; // 1: SDA, 0: SCLK

DDRF = 0xFC; // 7: digit1, 6: digit0, 5: oper led, 4: ok led, 3: error led, 2: motor, 1: nc, 0: AD input

DDRE = 0xFF;

PORTE = 0xFF;

TIMSK = 0x01; //

TCNT0 = 6; // timer0 1ms initial TCNT0 value

TCCR0 = 0x03; // clkT0S/32 (From prescaler)

 

DDRD |= (SDA + SCL);

sei();

 

Mbit.F_OpenCheck = 0;

Mbit.F_CloseCheck = 0;

 

_delay_ms(100);

 

PORTF |= OK_LED; // LED OFF

PORTF |= ERROR_LED; // LED OFF

ucI2Cd = 100;

 

PORTD &= ~WC;

_delay_us(2);

_delay_ms(500);

 

ucDisp = EEPLOAD_1BYTE(1);

Display(ucDisp);

SERVOR_Motor(0);

TX1_char(0x11);

while(1){

if(Mbit.F_OpenCheck == 1 &&  flag == 1) // open 검사

{

ucI2Cd = EEPLOAD_1BYTE(1);

if(ucDisp == ucI2Cd) // 비밀번호 일치

{

TX1_char(_KEY_OPEN);

SERVOR_Motor(-90); //Door Open

Mbit.F_OpenCheck = 0;

PORTF &= ~OK_LED;

PORTF |= ERROR_LED;

}

else{ // 비밀번호 불일치

SERVOR_Motor(0);

Mbit.F_OpenCheck = 0;

PORTF &= ~ERROR_LED;

v_clear();

}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 

 

}

else if(Mbit.F_CloseCheck == 1 && flag == 1) // close 검사

{

TX1_char(_KEY_CLOSE);

SERVOR_Motor(0);  //Door Close

Mbit.F_CloseCheck = 0;

PORTF |= OK_LED;

v_clear();

PORTF |= ERROR_LED;

if(uartToggle== 0){ // uart port on/off

if(uart_onOFF == 0){

rs232Init(9600);

uart_onOFF = 1;

}

PORTE &= ~_UART_LED;

unsigned char tempUartData1 = 0;

unsigned char tempuartData10 = 0;

unsigned char tempuartData = 0;

ucRs232Data_r = RX1_char_scan();

if(ucRs232Data_r != 0x00){

tempuartData = charIntDataFilter(ucRs232Data_r);

if(tempuartData > 10){

if(tempuartData == 11 && flag == 1) Mbit.F_OpenCheck = 1; // a

if(tempuartData == 11 && flag == 3){

calculator_s = ucDisp;

v_clear();

calculator_result();

}

if(tempuartData == 12 && flag == 1) Mbit.F_CloseCheck = 1; // b

if(tempuartData == 12 && flag == 3){

calculator_f = 0;

calculator_o = 0;

calculator_q = 1;

calculator_s = 0;

v_clear();

}

if(tempuartData == 13 && flag == 1){ // c - set | x | +

unRs232Init();

_delay_ms(10);

EEPSAVE_1BYTE(1,ucDisp); 

_delay_ms(10);

rs232Init(9600);

}

if(tempuartData == 13 && flag == 3){

calculator_o = '+';

if(calculator_q == 1){

calculator_f = ucDisp;

calculator_q = 2;

v_clear();

}

else {

calculator_s = ucDisp;

v_clear();

calculator_result();

}

}

if(tempuartData == 14 && flag == 1){ // d - read | x | -

unRs232Init();

_delay_ms(10);

v_clear();

ucDisp = EEPLOAD_1BYTE(1); 

_delay_ms(10);

rs232Init(9600);

}

if(tempuartData == 14 && flag == 3){

calculator_o = '-';

if(calculator_q == 1){

calculator_f = ucDisp;

calculator_q = 2;

v_clear();

}

else{

calculator_s = ucDisp;

v_clear();

calculator_result();

}

}

if(tempuartData == 15){ // e mode select

flag++;

if(flag == 4) flag = 1;

}

}

if(tempuartData < 10){

ucKeyCnt = 0;

Mbit.F_key_chg = 1;

ucKeyValue = tempuartData;

}

}

}

else{

unRs232Init();

uart_onOFF = 0;

PORTE |= _UART_LED;

}

if(flag == 2) // mode 2 - ADC 동작 시작

{

ADC_init();

ucDisp = ADC_Load();

flag3_S = 1;

}

if(flag == 3 && flag3_S == 1){

v_clear();

calculator_f = 0;

calculator_o = 0;

calculator_q = 1;

calculator_s = 0;

flag3_S = 0;

}

// 공통 부분

Display(ucDisp);

key_check();

if(Mbit.F_key_chg){ // 자리수 연산 -> 계산기와 도어락 공용 사용

Mbit.F_key_chg = 0;

ucDisp = ucPreKey * 10 + ucKeyValue;

ucPreKey = ucKeyValue;

}

if(Mbit.F_OPER_LED){ // LED 점멸

Mbit.F_OPER_LED = 0;

PORTF ^= OPER_LED;

}

switch(flag){ // flag 상태를 LED 표시

case  1 :

PORTE &= ~_DOORLOOK_LED;

PORTE |= _CALCULATOR_LED | _ADC_DIS_LED;

break;

case  2 :

PORTE &= ~_ADC_DIS_LED;

PORTE |= _DOORLOOK_LED | _CALCULATOR_LED;

break;

case  3 :

PORTE &= ~_CALCULATOR_LED;

PORTE |= _ADC_DIS_LED | _DOORLOOK_LED;

break;

}

}

}