당근보드의 디스플레이 보드에는 4개의 FND와 8개의 LED(8개중 동시에 사용가능한 LED는 4개)가 있습니다.
또한 메인보드에는 DS1307과 32.768khz의 크리스탈이 달려 있습니다.
이제 이 소자들을 활용하여 당근보드를 시계로 사용해 보겠습니다.

당근보드 디스플레이부의 모습.
당근보드에는 위와 같은 디스플레이부가 있습니다. 보시다시피 8개의 LED가 있으며 4개의 점퍼 설정으로 시계처럼 LED를 사용할것인지, 아니면 밑에 4개의 LED가 일렬로 있는 부분을 사용할 것인지 정할수 있습니다.
저는 점퍼를 모두 위에 연결하여 시계부분에 있는 녹색1개, 노란색1개, 빨간색2개를 사용하겠습니다.
그리고 당연히 4개의 FND를 사용해야겠지요.
제가 쓰는 당근보드는 보드 색이 녹색입니다.(위 사진은 당근이의AVR갖고놀기 카페에서 가져왔습니다) 그리고 LED를 고휘도 LED로 달아놓았지요.. 볼땐 멋있었는데 시계로 해놓으니 눈아파서 못보겠네요.ㅡㅡ;
아무튼 녹색 LED를 '오전'을 표시하는 LED로, 노란색 LED를 '오후'를 표시하는 LED로 사용하겠습니다.
또한 중간의 빨간색 2개의 LED는 약 0.5초 간격으로 깜빡이는 용도로 사용합니다.
시계IC인 DS1307은 32.768Khz 크리스탈과 함께 사용하며, 년, 월, 일, 요일, 시, 분, 초 를 나타낼 수 있습니다.
통신 방식은 I2C(TWI) 이며, DATASHEET는 아래에서 다운 받을수 있습니다.
I2C는 따로 열심히 공부하셔야 하구요, 저는 대충만 공부하고 소스를 구해다가 입맞에 맞게 고쳐 쓴 것입니다...ㅎ
제가 사용한 소스를 공개합니다. 이 소스는 엄청나게 큰 문제점이 있는데요.
시간 설정이 안된다는 겁니다. 그래서 소스를 넣을때 한번은 시간을 설정한 소스를 한번 넣어주고, 그담에 시간설정 부분이 없는 소스를 넣어줘 사용하면 됩니다. ㅎㅎ 시간 설정하는건 귀찮아서 넣지 않았습니다.ㅡㅡ;
그리고 이상하게 전원을 끊었다가 넣어주면 I2C 통신이 안되는가 봅니다. FND에 이상한 값이 출력됩니다.
이럴땐 백업 배터리 입력핀인 3번핀을 GND에 연결시켜준 후 리셋버튼을 누르면 또 잘 동작 하더군요...;;
왜이런지 아직 원인을 모르겠습니다. 데이터시트엔 백업배터리를 사용하지 않으면 Vbat 를 GND에 연결하라고 돼있길래 그리 해보니 되긴 하는데 전 백업배터리도 있고,, 배터리가 다 닳았나...ㅡㅡ;;;;;
아무튼 소스를 공개합니다~ 자자자잔!
#include <avr/io.h>
#include <stdio.h>
#include <carroty/delay.h>
#include <carroty/fnd.h>
unsigned char number_array[16]= { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, };
unsigned char fnd_sel_array[4]= { 0,0,0,0,};
unsigned char hour, min;
int n1000, n100, n10, n, time;
void rtc_write(unsigned char address, unsigned char byte) {
delay_us(6);
TWCR = 0xA4; // START condition
while(((TWCR & 0x80) == 0x00) || (TWSR & 0xF8) != 0x08);
TWDR = 0xD0;
TWCR = 0x84; // MT_SLA_ACK
while(((TWCR & 0x80) == 0x00) || (TWSR & 0xF8) != 0x18);
TWDR = address;
TWCR = 0x84; // MT_DATA_ACK
while(((TWCR & 0x80) == 0x00) || (TWSR & 0xF8) != 0x28);
TWDR = byte;
TWCR = 0x84; // MT_DATA_ACK
while(((TWCR & 0x80) == 0x00) || (TWSR & 0xF8) != 0x28);
TWCR = 0x94; // STOP condition
}
unsigned char rtc_read(unsigned char address) {
delay_us(6);
unsigned char byte;
TWCR = 0xA4; // START condition
while(((TWCR & 0x80) == 0x00) || (TWSR & 0xF8) != 0x08);
TWDR = 0xD0;
TWCR = 0x84; // MT_SLA_ACK
while(((TWCR & 0x80) == 0x00) || (TWSR & 0xF8) != 0x18);
TWDR = address;
TWCR = 0x84; // MT_DATA_ACK
while(((TWCR & 0x80) == 0x00) || (TWSR & 0xF8) != 0x28);
TWCR = 0xA4; // RESTART condition
while(((TWCR & 0x80) == 0x00) || (TWSR & 0xF8) != 0x10);
TWDR = 0xD1;
TWCR = 0x84; // MR_SLA_ACK
while(((TWCR & 0x80) == 0x00) || (TWSR & 0xF8) != 0x40);
TWCR = 0x84; // MR_DATA_NOACK
while(((TWCR & 0x80) == 0x00) || (TWSR & 0xF8) != 0x58);
byte = TWDR;
TWCR = 0x94; // STOP condition
return byte;
}
void display_fnd(unsigned char number, unsigned char fnd_select) {
PORTB= number;
PORTC= fnd_select;
}
void time_print(unsigned int value) {
n1000=value/1000;
n100=(value-(value/1000*1000))/100;
n10=(value-(value/100*100))/10;
n=value-(value/10*10);
int g;
for(g=0;g<10;g++){
display_fnd(number_array[n1000], fnd_sel_array[0]); delay_ms(3);
display_fnd(number_array[n100], fnd_sel_array[1]); delay_ms(3);
display_fnd(number_array[n10], fnd_sel_array[2]); delay_ms(3);
display_fnd(number_array[n], fnd_sel_array[3]); delay_ms(3);
}
}
void led_init(void) {
DDRB= 0xFF;
DDRC= 0xF0;
DDRA= 0xF0;
}
int main(void) {
TWBR= 72;
TWSR= 0x00;
TWCR= 0x04;
number_array[0]= NUMBER_0;
number_array[1]= NUMBER_1;
number_array[2]= NUMBER_2;
number_array[3]= NUMBER_3;
number_array[4]= NUMBER_4;
number_array[5]= NUMBER_5;
number_array[6]= NUMBER_6;
number_array[7]= NUMBER_7;
number_array[8]= NUMBER_8;
number_array[9]= NUMBER_9;
fnd_sel_array[0]= FND_SEL_1;
fnd_sel_array[1]= FND_SEL_2;
fnd_sel_array[2]= FND_SEL_3;
fnd_sel_array[3]= FND_SEL_4;
led_init();
/* 시간 설정 부분.
rtc_write(0x06,0x09);
rtc_write(0x05,0x09);
rtc_write(0x04,0x25);
rtc_write(0x03,0x05);
rtc_write(0x02,0x02);
rtc_write(0x01,0x17);
rtc_write(0x00,0x00); */
PORTA=0xF0;
int h=0;
while(1) {
hour= rtc_read(0x02);
hour= ((hour >>4) & 0x07)*10 + (hour & 0x0f);
min= rtc_read(0x01);
min= ((min >>4) & 0x07)*10 + (min & 0x0f);
if(hour>12){
//hour=hour-12;
PORTA=PORTA&0b11011111;
PORTA=PORTA|0b00010000;
}
else {
PORTA=PORTA&0b11101111;
PORTA=PORTA|0b00100000;
}
time=hour*100+min;
time_print(time);
h++;
if(h>4) {
h=0;
PORTA^=0xC0;
}
}
}
ㅎㅎㅎ 코딩실력이 부족해 소스가 난잡합니다.ㅡㅡ; 이해하시길;;;ㅎㅎ
그럼 동작 하는 모습을 보시죠~
현재 새벽이므로 오전이라는 표시인 노란색 LED가 들어와있습니다.
그리고 빨간색 LED 2개가 깜빡이는데 0.5초마다 깜빡이는건 아니고 그냥 대충 깜빡이는것입니다...;;
하지만 시계는 정확하지요.ㅎㅎㅎ
댓글을 달아 주세요
그런데요. 설정값을 변경했는데 ic가 죽었다고 하기엔 좀 그런거같아보여요. 다시 설정값만 해주면 되는거 아닌가요 ^^; 대부분 타거나 열받아서 죽는게 아닌가요? 그런건 복귀 가능한가요?
물론 설정값을 바꿨다고 IC가 죽는것은 아니지요.
위에서 제가 설정을 한 것은 외부 크리스탈이 창작되어있지 않은 상태에서 퓨즈비트를 외부 크리스탈로 설정한 것입니다.
이 경우 실제로 ATmega128이나 같은 atmega 계열 ic들은 동작을 하지 않게 됩니다.
이런경우 AVR Studio 에서 hex파일을 write하려고 하면
device missing or unknown device [-24] 라는 메시지가 뜨게 되지요.
실제로 물리적으로 부셔졌거나, 과전류로 인해 IC가 타버린 경우가 아니라면 atmega계열의 mcu가 동작하지 않는 이유는 사용자나 또는 다른 이유로(EMI 영향 등..) 퓨즈비트 셋팅이 잘못되어 장치인식을 못하게 되는 경우가 대부분입니다.
이런경우 강제로 외부 클럭을 넣어주면 ic를 다시 동작하게 할수 있는데요, 이를 인공호흡이라 합니다. 보통의 크리스탈로는 인공호흡을 하지 못하고, 오실레이터나 펑션 제너레이터같이 펄스를 만들어주는 장치로 인공호흡용 클럭을 만듭니다. 위 예제는 avr을 이용해 펄스를 만들어 인공호흡을 한 예제 입니다.
쉽게말해 퓨즈비트 이상으로 동작하지 않는 avr칩을 인공적으로 클럭을 만들어 강제로 넣어주지 않게되면 못쓰게 되서 죽었다고 표현하는 것이죠. 물론 설정값만 다시 정상값으로 변경해주면 됩니다.
하지만, 저런 과정 없이 설정값을 다시 셋팅할수 있을까요? 인식조차 되지 않을것입니다.
인공호흡이 이런의미였네요
ㅎㅎ저도 AVR을 처음 시작할때 인공호흡을 한다는말이 이해가 가지 않았었습니다.ㅋㅋ