Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * led_clock.c
- *
- * Created: 24.12.2018 19:24:51
- * Author : Redfern.89
- */
- // Частота проца в герцах
- #ifndef F_CPU
- #define F_CPU 16000000UL
- #endif
- #include <avr/io.h>
- #include <util/delay.h>
- #include <avr/interrupt.h>
- #include <math.h>
- // Настройки портов ввода-вывода
- #define RCLK_DDR DDRD //
- #define SCLK_DDR DDRD // SSSSSSSSSS PPPPPPPPP III
- #define DATA_DDR DDRD // S P P I
- #define RCLK_PORT PORTD // S P P I
- #define SCLK_PORT PORTD // SSSSSSSSSS P PPPPPPPP I
- #define DATA_PORT PORTD // S P I
- #define RCLK PD5 // S P I
- #define SCLK PD6 // SSSSSSSSSS P III
- #define DATA PD7 //
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- #define I2C_DDR DDRC //
- #define I2C_PORT PORTC // 2222
- #define I2C_PIN PINC // I 2 ccc
- #define I2C_SCL PC0 // I 2222 c
- #define I2C_SDA PC1 // I 2 c
- #define I2C_ACK 0 // I 2222 ccc
- #define I2C_NACK 1 //
- /* ~~~~~~~~~~~~~~~~~~~~ МАКРОСЫ ~~~~~~~~~~~~~~~~~~~~ */
- // Упарвление защелкой и сдвигом регистров
- #define _74hc595_RegisterLatch(code) { RCLK_PORT &= (1 << RCLK); code; RCLK_PORT |= (1 << RCLK); }
- #define _74hc595_RegisterShift() { SCLK_PORT &= ~(1 << SCLK); SCLK_PORT |= (1 << SCLK); }
- // Управление i2c-портами
- #define ONE_SCL { I2C_DDR &= ~(1 << I2C_SCL); I2C_PORT |= (1 << I2C_SCL); }
- #define NULL_SCL { I2C_DDR |= (1 << I2C_SCL); I2C_PORT &= ~(1 << I2C_SCL); }
- #define ONE_SDA { I2C_DDR &= ~(1 << I2C_SDA); I2C_PORT |= (1 << I2C_SDA); }
- #define NULL_SDA { I2C_DDR |= (1 << I2C_SDA); I2C_PORT &= ~(1 << I2C_SDA); }
- #define I2C_DELAY { _delay_ms(1); }
- // Управление таймером 0 для IRDA
- #define TIMER0_START { TCCR0B = (1 << CS01) | (1 << CS00); }
- #define TIMER0_STOP { TCCR0B = 0x00; }
- // Данные о сегментах индикатора (LSBFIRST)
- uint8_t digits[11] = {// A
- 0b11000000, //1 #########
- 0b11111001, //2 # #
- 0b10100100, //3 F # # B
- 0b10110000, //4 # G #
- 0b10011001, //5 #########
- 0b10010010, //6 # #
- 0b10000010, //7 E # # C
- 0b11111000, //8 # #
- 0b10000000, //9 #########
- 0b10010000, //0 D ##
- 0b11111111 //8. dp
- };
- // Данные о группах светодиодов
- const uint8_t groups[4] = {
- 0b11111011,
- 0b11111101,
- 0b11110111,
- 0b11101111
- };
- /* Кое-какие глобальные переменные */
- unsigned char NC = 0b11111111;
- unsigned char display_data[4] = {0b11111111, 0b11111111, 0b11111111, 0b11111111};
- const static int max_groups = 4;
- static int display_pos = 0;
- volatile int NEC_REPEAT_FLAG = 0;
- volatile int NEC_START_FLAG = 0;
- volatile int NEC_IR_DONE = 0;
- /* Протокол NEC */
- volatile unsigned long int NEC_SCLK = 0; // Тактовые синхроимпульсы (64 мкс)
- volatile unsigned long int NEC_RECV_CNT = 0; // Кол-во принятых битов
- const static int NEC_MIN_PREAMBLE = 212; // Преамбула+пауза (минимальное время)
- const static int NEC_MAX_PREAMBLE = 216; // Преамбула+пауза (максимальное время)
- const static int NEC_MIN_REPEAT = 178;
- const static int NEC_MAX_REPEAT = 180;
- const static int NEC_MIN_ONE_BIT = 34;
- const static int NEC_MAX_ONE_BIT = 46;
- const static int NEC_MIN_NULL_BIT = 17;
- const static int NEC_MAX_NULL_BIT = 19;
- const static int NEC_MAX_RESET_OVF = 1200;
- const static int NEC_PACKET_LENGTH = 32;
- unsigned char NEC_RESPONSE_DATA[4] = {0b00000000, 0b00000000, 0b00000000, 0b00000000};
- /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Shift registers functions
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
- // Отправка данных в регистр
- void _74hc595_SPI_send(char data) {
- int i;
- unsigned char val;
- for (i = 0; i < 8; i++) {
- val = !!(data & (1 << (7 - i)));
- if (val) DATA_PORT |= (1 << DATA); else DATA_PORT &= (1 << DATA);
- _74hc595_RegisterShift();
- }
- }
- // Отправка данных в регистры и защелкивание
- void _74hc595_RegisterWrite(unsigned char data1, unsigned char data2) {
- _74hc595_RegisterLatch({
- _74hc595_SPI_send(data1);
- _74hc595_SPI_send(data2);
- });
- }
- // Отправка данных в регистры с защелкиванием (2.0)
- void _74hc595_RegisterWrite2(unsigned char* data, int registrs_count) {
- unsigned int i = 0;
- _74hc595_RegisterLatch({
- for (i = 0; i < registrs_count; i++) {
- _74hc595_SPI_send(data[i]);
- }
- });
- }
- /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- i2c Functions
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
- // Условие STOP
- unsigned char i2c_stop(void) {
- unsigned char error = 0;
- NULL_SCL;
- I2C_DELAY;
- NULL_SDA;
- I2C_DELAY;
- ONE_SCL;
- I2C_DELAY;
- ONE_SDA;
- I2C_DELAY;
- if (( I2C_PIN & (1 << I2C_SDA)) == 0) error = 2;
- if (( I2C_PIN & (1 << I2C_SCL)) == 0) error |= 1;
- I2C_DELAY;
- I2C_DELAY;
- I2C_DELAY;
- I2C_DELAY;
- return error;
- }
- // Условие START
- void i2c_start(void) {
- NULL_SDA;
- I2C_DELAY;
- NULL_SCL;
- I2C_DELAY;
- }
- // Условие RESTART
- void i2c_restart(void) {
- ONE_SDA;
- I2C_DELAY;
- ONE_SCL;
- I2C_DELAY;
- NULL_SDA;
- I2C_DELAY;
- NULL_SCL;
- I2C_DELAY;
- }
- // Инициализация шины i2c
- void i2c_init(void) {
- ONE_SDA;
- ONE_SCL;
- i2c_stop();
- }
- // Отправка байта по шине i2c
- unsigned char i2c_write(unsigned char data) {
- unsigned char i;
- unsigned char ask = I2C_ACK;
- for (i = 0; i < 8; i++) {
- if ((data & 0x80) == 0) { // Пиздец
- NULL_SDA;
- } else {
- ONE_SDA;
- }
- I2C_DELAY;
- ONE_SCL;
- I2C_DELAY;
- NULL_SCL;
- data = (data << 1);
- }
- ONE_SDA;
- I2C_DELAY;
- ONE_SCL;
- I2C_DELAY;
- if ((I2C_PIN & (1 << I2C_SDA)) == (1 << I2C_SDA)) {
- ask = I2C_NACK;
- } else {
- ask = I2C_ACK;
- }
- NULL_SCL;
- return ask;
- }
- // Чтение байта по шине i2c
- unsigned char i2c_read(unsigned char ask) {
- unsigned char byte = 0;
- unsigned char i;
- for (i = 0; i < 8; i++) {
- byte = (byte << 1);
- ONE_SCL;
- I2C_DELAY;
- if ((I2C_PIN & (1 << I2C_SDA)) == (1 << I2C_SDA)) byte |= 0x01;
- NULL_SCL;
- I2C_DELAY;
- }
- if (ask == I2C_ACK) {
- NULL_SDA;
- } else {
- ONE_SDA;
- }
- I2C_DELAY;
- ONE_SCL;
- I2C_DELAY;
- NULL_SCL;
- ONE_SDA;
- return byte;
- }
- /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- DS1307 Functions
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
- // Чтение данных из DS1307
- unsigned char DS1307_Read(unsigned char address, unsigned char data) {
- unsigned char res;
- i2c_start();
- res = i2c_write(0b11010000);
- if (!res) return 0;
- res = i2c_write(address);
- if (!res) return 0;
- i2c_start();
- res = i2c_write(0b11010001);
- if (!res) return 0;
- res = i2c_read(data);
- if (!res) return 0;
- i2c_stop();
- return 1;
- }
- /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- NEC 2.0 functions
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
- // Сброс данных по IRDA
- void NEC_Reset_IRDA() {
- TIMER0_STOP;
- NEC_START_FLAG = 0;
- NEC_REPEAT_FLAG = 0;
- NEC_RECV_CNT = 0;
- NEC_SCLK = 0;
- }
- // Таймер обработки длительности импульсов
- ISR (TIMER0_OVF_vect) {
- TCNT0 = 0xF0;
- if (++NEC_SCLK >= NEC_MAX_RESET_OVF) {
- NEC_SCLK = 0;
- NEC_REPEAT_FLAG = 0;
- NEC_START_FLAG = 0;
- TIMER0_START;
- }
- }
- // Обработчик внешнего прерывания
- ISR (INT0_vect) {
- TIMER0_START;
- if (NEC_SCLK >= NEC_MIN_PREAMBLE && NEC_SCLK < NEC_MAX_PREAMBLE) {
- NEC_START_FLAG = 1;
- NEC_REPEAT_FLAG = 0;
- }
- if ((NEC_SCLK >= NEC_MIN_REPEAT && NEC_SCLK < NEC_MAX_REPEAT) && NEC_START_FLAG) {
- NEC_START_FLAG = 0;
- NEC_REPEAT_FLAG = 1;
- }
- // Пожалуй, это самые уебансике места в программе...
- if ((NEC_SCLK >= NEC_MIN_ONE_BIT && NEC_SCLK < NEC_MAX_ONE_BIT) && NEC_START_FLAG) {
- NEC_RECV_CNT++;
- // Знаю, по-идиотски, умнее лень было придумывать
- if (NEC_RECV_CNT < 9) { // Биты 1-8
- NEC_RESPONSE_DATA[0] |= (1 << NEC_RECV_CNT);
- } else if (NEC_RECV_CNT >= 9 && NEC_RECV_CNT < 17) { // Биты 9-16
- NEC_RESPONSE_DATA[1] |= (1 << (NEC_RECV_CNT -9));
- } else if (NEC_RECV_CNT >= 17 && NEC_RECV_CNT < 25 ) { // Биты 17-24
- NEC_RESPONSE_DATA[2] |= (1 << (NEC_RECV_CNT - 17));
- } else if (NEC_RECV_CNT >= 25) { // Биты 25-32
- NEC_RESPONSE_DATA[3] |= (1 << (NEC_RECV_CNT - 25));
- }
- }
- NEC_SCLK = 0;
- if (NEC_RECV_CNT == NEC_PACKET_LENGTH) {
- NEC_Reset_IRDA();
- if ((NEC_RESPONSE_DATA[0] + NEC_RESPONSE_DATA[1] == 0xFF) && (NEC_RESPONSE_DATA[2] + NEC_RESPONSE_DATA[3] == 0xFF)) {
- NEC_IR_DONE = 1;
- }
- }
- }
- /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Main Functions
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
- // Динамическая индикация
- ISR (TIMER2_OVF_vect) {
- TCNT2 = 0xFA;
- display_pos = (display_pos + 1) % max_groups;
- unsigned char display[2] = {display_data[display_pos], groups[display_pos]};
- _74hc595_RegisterWrite2(display, 2);
- }
- // Подсчет времени
- ISR (TIMER1_OVF_vect) {
- }
- // Отрисовка цифр на дисплее
- void print_display(int hours, int minutes, int colon_blink) {
- if (hours == 0) {
- display_data[0] = digits[0];
- display_data[1] = colon_blink ? digits[0] | (1 << 0) : digits[0];
- } else if (hours >= 1 && hours <= 9) {
- display_data[0] = digits[0];
- display_data[1] = colon_blink ? digits[hours] | (1 << 0) : digits[hours];
- } else if (hours >= 10 && hours <= 99) {
- display_data[0] = digits[(unsigned int)round(hours % 100) / 10];
- display_data[1] = colon_blink ? digits[(unsigned int)round(hours % 10)] | (1 << 0) : digits[(hours % 10)];
- }
- if (minutes == 0) {
- display_data[2] = digits[0];
- display_data[3] = digits[0];
- } else if (minutes >= 1 && minutes <= 9) {
- display_data[2] = digits[0];
- display_data[3] = digits[minutes];
- } else if (minutes >= 10 && minutes <= 99) {
- display_data[2] = digits[(unsigned int)round(minutes % 100) / 10];
- display_data[3] = digits[(unsigned int)round(minutes % 10)];
- }
- }
- // Инициализация микроконтроллера
- void MCU_init() {
- // Инициализация портов ввода-вывода
- RCLK_DDR |= (1 << RCLK);
- SCLK_DDR |= (1 << SCLK);
- DATA_DDR |= (1 << DATA);
- // Инициализация внешнего прерывания (на спад)
- EICRA = (1 << ISC01);
- EIMSK = (1 << INT0);
- EIFR = (1 << INTF0);
- PCICR = 0x00;
- // Инициализация таймера/счестчика 0 для подсчета временного интервала между импульсами
- TCCR0B = (1 << CS01) | (1 << CS00);
- TIMSK0 = (1 << TOIE0);
- TCNT0 = 0xF0;
- // Иницмализация таймера/счетчика 1 для работы интерфейса
- TCCR1B = (1 << CS10) | (1 << CS11);
- TIMSK1 = (1 << TOIE1);
- TCNT1 = 0xFFFE;
- // Инициализация таймера/счестчика 2 для динамической индикации
- TCCR2B = (1 << CS20);
- TIMSK2 = (1 << TOIE2);
- TCNT2 = 0xFA;
- // Инициализация i2c
- i2c_init();
- }
- int main(void) {
- asm("CLI");
- MCU_init();
- asm("SEI");
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment