이전에 대학교 때, 작성한 도어락 과제입니다.
기능들은 한 기판에 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;
}
}
}