Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <avr/io.h>
- #include <util/delay.h>
- #include <EEPROM.h>
- // Сигналы управления сдвиговыми регистрами
- #define RCLK 6 // Защелка
- #define SCLK 7 // Тактирование
- #define DATA 5 // Данные
- // Тактовая частота процессора 16MHz
- #define F_CPU 16000000UL
- #define BAUD 9600
- #define MYUBRR F_CPU / 16 / BAUD - 1
- // Макрос управления защелкой
- #define _74hc595_registerLatch(code) { PORTD &= ~(1 << RCLK); code; PORTD |= 1 << RCLK; }
- // Макрос управления сдвигом регистров
- #define _74hc595_registerShift() { PORTD &= ~(1 << SCLK); PORTD |= (1 << SCLK); }
- // Данные о сегментах индикаторов
- const uint8_t digits[11] = {// A
- 0b11000000, // #########
- 0b11111001, // # #
- 0b10100100, // F # # B
- 0b10110000, // # G #
- 0b10011001, // #########
- 0b10010010, // # #
- 0b10000010, // E # # C
- 0b11111000, // # #
- 0b10000000, // #########
- 0b10010000, // D ##
- 0b11111111 // dp
- };
- // Данные о группах светодиодов (16 бит)
- const uint16_t groups[15] = {
- /* -------- 3 DIGIT DISPLAY -------- */
- 0b0000010000000000, // DIGIT 1 (0)
- 0b0000001000000000, // DIGIT 2 (1)
- 0b0000000100000000, // DIGIT 3 (2)
- /* -------- 6 DIGIT DISPLAY -------- */
- 0b0000000010000000, // DIGIT 1 (3)
- 0b0000000001000000, // DIGIT 2 (4)
- 0b0000000000100000, // DIGIT 3 (5)
- 0b0000000000010000, // DIGIT 4 (6)
- 0b0000000000001000, // DIGIT 5 (7)
- 0b0000000000000100, // DIGIT 6 (8)
- /* -------- 40 Leds Scale -------- */
- 0b0010000000000000, // SCALE 1 (9)
- 0b0001000000000000, // SCALE 2 (10)
- 0b0000100000000000, // SCALE 3 (11)
- 0b0000000000000010, // SCALE 4 (12)
- 0b0000000000000001 // SCALE 5 (13)
- };
- // Данные о светодиодах в шкале
- const uint8_t scale_leds[9] = {
- 0b11111111, // 0 LED's
- 0b11111110, // 1 LED's
- 0b11111100, // 2 LED's
- 0b11111000, // 3 LED's
- 0b11110000, // 4 LED's
- 0b11100000, // 5 LED's
- 0b11000000, // 6 LED's
- 0b10000000, // 7 LED's
- 0b00000000 // 8 LED's
- };
- unsigned int NC = 0b11111111; // Пустое значение
- unsigned int display_position = 0; // Текущее значение на экране / группа
- unsigned int CNT_Impulse = 0; // Колличество импульсов с датчика
- unsigned int CountImpulse = 10; // Точность точность измерений
- unsigned int CNT_OVF = 0; // Переполнения
- unsigned int TMP_CNT_OVF = 0; // Для сравнения с предыдущими переполнениями
- unsigned int TMP_TCNT = 0; // Запоминаем, сколько осталось до переполнения
- unsigned int ImpulsePerRotate = 6; // Колличество импульсов на 1 оборот колеса
- unsigned int CNT_Mileage_Impulse = 0; // Для подсчета импульсов пробега
- unsigned int total_scale_leds = 40; // Колличество светодиодов в шкале
- unsigned int leds_per_group = 8; // Колличество светодиодов на группу
- unsigned int MaximumSpeedCalc = 200; // Максимальная расчетная скорость
- unsigned int factorial = 0; // Факториал (сопоставление скорость/шкала)
- unsigned int speed_scale = 0; // Скорость на шкале светодиодов
- unsigned int display_groups_cnt = 14; // Колличество групп светодиодов
- unsigned int btn_tick_count = 0; // Пишем кол-во тиков программы для обработки долгого нажатия
- unsigned int btn_delay_titck = 5; // Кол-во тиков для долгого нажатия
- unsigned int btn_bounce_delay = 50; // Время дребезга контактов в мс
- unsigned int odometr_mode = 0; // Режим одометра. Общий/текущий
- float LengthCircle = 180.6128F; // Размер колеса. R13 175/70
- float current_mileage = 0.0F; // Текущий пробег
- float total_milleage = 0.0F; // Общий пробег
- float ee_milleage = 0.0F; // пробег из EEPROM
- float Speed = 0.0F; // Текущая скорость
- bool speed_flag = false; // Флаг измерения скорости
- bool ignition_flag = false; // флаг включенного зажигания
- bool eeprom_read_flag = false; // Флаг чтения из EEPROM
- uint8_t display_data[14] = {NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC};
- // Отправка данных по SPI
- void _74hc595_SPI_send(uint8_t data) {
- for (uint8_t i = 0; i < 8; i++) {
- byte value = !!(data & (1 << (7 - i)));
- if (value) PORTD |= 1 << DATA; else PORTD &= ~(1 << DATA);
- _74hc595_registerShift();
- }
- }
- // Запись в регистры
- void _74hc595_registerWrite(uint16_t groups, uint8_t segments) {
- // "Защелкиваем" данные в регистры
- _74hc595_registerLatch({
- _74hc595_SPI_send(groups >> 8); // Сначала старший байт
- _74hc595_SPI_send((groups) & 0xFF); // Затем младший байт
- _74hc595_SPI_send(segments); // Теперь Один байт, отвечающий за сегменты
- });
- }
- // Описание таймера индикации
- ISR (TIMER1_OVF_vect) {
- TCNT1 = 64456; // Начинаем отсчет с 64456
- display_position = (display_position + 1) % display_groups_cnt; // Счиатем до 14 и сбрасываемся
- _74hc595_registerWrite(groups[display_position], display_data[display_position]); // Отправляем в регистры текущие данные (Группа, сегменты)
- }
- // Описание таймера подсчета импульсов
- ISR (TIMER0_OVF_vect) {
- CNT_OVF++; // Прибавляем на 1 при каждом переполнении
- }
- // Описание внешнего прерывания
- ISR (INT0_vect) {
- // Считаем пробег
- // Как только кол-во импульсов стало равно одному обороту колеса
- // Прибавляем ктекущему пробегу длину колеса и преводим в километры
- if (++CNT_Mileage_Impulse >= ImpulsePerRotate) {
- current_mileage = current_mileage + (LengthCircle * 0.00001);
- CNT_Mileage_Impulse = 0;
- }
- // Счиатаем данные для расчета скорости
- if (++CNT_Impulse >= CountImpulse) {
- TMP_TCNT = TCNT0; // Запоминаем, сколько осталось до переполнения
- TMP_CNT_OVF = CNT_OVF; // Запоминаем кол-во переполнений
- /* Обнуляем текущие счетчики */
- CNT_OVF = 0;
- TCNT0 = 0;
- CNT_Impulse = 0;
- speed_flag = true;
- }
- }
- ISR (INT1_vect) {
- //current_mileage = 0.0F;
- }
- // Заполнение участка массива индикации нулями
- void fill_display(int offset, int count) {
- if (count >= offset) {
- for (int i = offset; i < count; i++) {
- display_data[i - offset] = NC;
- }
- }
- }
- // Как я с этим заебался. Вывод данных на шкалу светодиодов
- void printLedScale(float leds) {
- int led = 0;
- int unusedGroups = 0;
- int groups = 0;
- int current = 0;
- if (leds > total_scale_leds) leds = total_scale_leds;
- groups = ceil(leds / leds_per_group);
- if (leds > 0) {
- for (int i = 0; i < groups; i++) {
- current = i +1;
- if (current |= groups) {
- display_data[i +9] = scale_leds[leds_per_group -1];
- } else {
- led = leds - (leds_per_group * (groups - 1) ) -1;
- display_data[i +9] = scale_leds[led];
- }
- unusedGroups = leds_per_group - groups;
- if (unusedGroups > 0) {
- fill_display(groups +9, unusedGroups);
- }
- }
- }
- }
- // Муторная процедура отображения данных на 3х цифровом индикаторе
- void print3digitDisplay(int number) {
- if (number == 0) {
- display_data[0] = (digits[0] & ~(1 << 7));
- display_data[1] = digits[0];
- display_data[2] = digits[0];
- } else if (number >= 1 && number <= 9) {
- display_data[0] = digits[number];
- fill_display(1, 2);
- } else if (number >= 10 && number <= 99) {
- display_data[0] = digits[round(number % 100) / 10];
- display_data[1] = digits[round(number % 10)];
- fill_display(2, 1);
- } else if (number >= 100 && number <= 999) {
- display_data[0] = digits[round(number / 100) % 10];
- display_data[1] = digits[round(number % 100) / 10];
- display_data[2] = digits[round(number % 10)];
- }
- }
- // Еще более мутная тема для 6ти цифр
- void print6digitDisplay(float number) {
- if (number <= 9) {
- display_data[3] = (digits[(int)floor(number)] & ~(1 << 7));
- display_data[4] = digits[(int)floor(number * 10.0F) % 10];
- fill_display(4, 3);
- } else if (number >= 10 && number <= 99) {
- display_data[3] = digits[(int)floor(number) % 100 / 10];
- display_data[4] = digits[(int)floor(number) % 10] & ~(1 << 7);
- display_data[5] = digits[(int)floor(number * 10.0F) % 10];
- fill_display(3, 3);
- } else if (number >= 100 && number <= 999) {
- display_data[3] = digits[(int)floor(number) % 1000 / 100];
- display_data[4] = digits[(int)floor(number) % 100 / 10];
- display_data[5] = digits[(int)floor(number) % 10] & ~(1 << 7);
- display_data[6] = digits[(int)floor(number * 10.0F) % 10];
- fill_display(6, 2);
- } else if (number >= 1000 && number <= 9999) {
- display_data[3] = digits[(int)floor(number / 1000)];
- display_data[4] = digits[(int)floor(number) / 100 % 10];
- display_data[5] = digits[(int)floor(number) % 100 / 10];
- display_data[6] = digits[(int)floor(number) % 10] & ~(1 << 7);
- display_data[7] = digits[(int)floor(number * 10.0F) % 10];
- fill_display(7, 1);
- } else if (number >= 10000 && number <= 99999) {
- display_data[3] = digits[(long int)floor(number) / 10000];
- display_data[4] = digits[(long int)floor(number / 1000) % 10];
- display_data[5] = digits[(long int)floor(number / 100) % 10];
- display_data[6] = digits[(long int)floor(number / 10) % 10];
- display_data[7] = digits[(long int)floor(number) % 10] & ~(1 << 7);
- display_data[8] = digits[(long int)floor(number * 10.0F) % 10];
- } else if (number >= 100000 && number <= 999999) {
- display_data[3] = digits[(long int)floor(number) / 100000];
- display_data[4] = digits[(long int)floor(number / 10000) % 10];
- display_data[5] = digits[(long int)floor(number / 1000 )% 10] & ~(1 << 7); // Ставим точку после 3го разряда (ex. 327.680)
- display_data[6] = digits[(long int)floor(number) % 1000 / 100];
- display_data[7] = digits[(long int)floor(number) % 100 / 10];
- display_data[8] = digits[(long int)floor(number) % 10];
- }
- }
- // Тетст всего экрана (все группы и сегменты)
- void test_display(bool null_byte = false) {
- int i;
- for (i = 0; i < 14; i++) {
- if (!null_byte) display_data[i] = ~NC;
- else display_data[i] = NC;
- }
- }
- void USART_Transmit ( unsigned char data ) {
- while (!(UCSR0A & (1 << UDRE0)));
- UDR0 = data;
- }
- void USART_SendString( char *StringPtr ) {
- while (*StringPtr != 0x00) {
- USART_Transmit(*StringPtr);
- StringPtr++;
- }
- }
- float eeprom_read_float(int addr) {
- byte raw[4];
- for (byte i = 0; i < 4; i++) {
- raw[i] = EEPROM.read(addr + i);
- }
- float &num = (float&)raw;
- return num;
- }
- void eeprom_write_float(int addr, float num) {
- byte raw[4];
- (float&)raw = num;
- for (byte i = 0; i < 4; i++) EEPROM.write(addr + i, raw[i]);
- }
- // Основная программа
- int main () {
- // SPI - выводы для регистров
- DDRD = 0b11100000;
- // Инициализация таймера 0 (Подсчет импульсов) 8bit
- TIMSK0 = (1 << TOIE0); // Разрешаем таймер по переполнению
- TCCR0B = (1 << CS12) | (0 << CS11) | (1 << CS10); // Предделитель /1024
- // 16000000 / 1024 = 15625
- // Таймер 1 (динамической индикации) 16 bit
- TIMSK1 = (1 << TOIE1);
- TCCR1B = (0 << CS12) | (1 << CS11) | (0 << CS10); // Предделитель /8
- TCNT1 = 64456;
- // Инициализация внешнего прерывания (на спад) на INT0
- EICRA |= (1 << ISC01);
- EIMSK |= (1 << INT0);
- // Инициализация внешнего прерывания (на спад) на INT1
- EIMSK |= (1 << INT1);
- // Инициализация USART
- UBRR0H = (unsigned char) (MYUBRR >> 8);
- UBRR0L = (unsigned char) MYUBRR;
- UCSR0B = (1 << RXEN0) | (1 << TXEN0);
- UCSR0C = (1 << USBS0) | (1 << UCSZ00);
- current_mileage = eeprom_read_float(0);
- unsigned long int i = 0;
- // Вечный цикл
- while (1) {
- // проверка на включеннре зажигание
- if (~PIND & (1 << 4)) {
- ignition_flag = true;
- if (!eeprom_read_flag) {
- current_mileage = eeprom_read_float(0);
- eeprom_read_flag = true;
- }
- asm("SEI");
- } else {
- test_display(true);
- ignition_flag = false;
- eeprom_read_flag = false;
- eeprom_write_float(0, current_mileage);
- asm("CLI");
- }
- if (ignition_flag) {
- // _delay_ms(500);
- /*
- Расчет скорости. пройденное расстояние делим Дельту времени и переводим в часы. Вот, как это сделалнно
- Таймер TIMER0 настроен на предделитель /1024, значит он будет рабоать на частоте 15.625KHz
- Счиатем так: Колличество переполнений умножаем на разрядность таймера, прибавляем остатки от незаконченного
- переполнения, делим на частоту таймера и переводим в часы. Это расчет дельты времени
- */
- Speed = ((( CountImpulse / ImpulsePerRotate ) * LengthCircle) / (( TMP_CNT_OVF * 256 + TMP_TCNT) / 15625.0F)) * 0.036F;
- factorial = (MaximumSpeedCalc / total_scale_leds);
- speed_scale = floor(Speed / factorial);
- // Выводим текущие значения
- print6digitDisplay((float) current_mileage);
- print3digitDisplay(Speed);
- printLedScale(speed_scale);
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment