Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <avr/io.h>
- #include <util/delay.h>
- // Сигналы управления сдвиговыми регистрами
- #define RCLK 6 // Защелка
- #define SCLK 7 // Тактирование
- #define DATA 5 // Данные
- // Тактовая частота процессора 16MHz
- #define F_CPU 16000000UL
- // Макрос управления защелкой
- #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
- };
- uint8_t 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; // Скорость на шкале светодиодов
- float LengthCircle = 180.6128F; // Размер колеса. R13 175/70
- float mileage = 0.0F; // Текущий пробег
- float Speed = 0.0F; // Текущая скорость
- bool speed_flag = false; // Флаг измерения скорости
- 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) % 14; // Счиатем до 14 и сбрасываемся
- _74hc595_registerWrite(groups[display_position], display_data[display_position]); // Отправляем в регистры текущие данные (Группа, сегменты)
- }
- // Описание таймера подсчета импульсов
- ISR (TIMER0_OVF_vect) {
- CNT_OVF++;
- }
- // Описание внешнего прерывания
- ISR (INT0_vect) {
- // Считаем пробег
- // Как только кол-во импульсов стало равно одному обороту колеса
- // Прибавляем ктекущему пробегу длину колеса и преводим в километры
- if (++CNT_Mileage_Impulse >= ImpulsePerRotate) {
- mileage = 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;
- }
- }
- // Заполнение участка массива индикации нулями
- void fill_display(int offset, int count) {
- for (int i = offset; i < count; i++) {
- display_data[i] = 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[7];
- } 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(unsigned long int number) {
- if (number <= 9) {
- display_data[3] = digits[number];
- fill_display(4, 5);
- } else if (number >= 10 && number <= 99) {
- display_data[3] = digits[round(number % 100) / 10];
- display_data[4] = digits[round(number % 10)];
- fill_display(5, 4);
- } else if (number >= 100 && number <= 999) {
- display_data[3] = digits[round(number % 100) / 10];
- display_data[4] = digits[round(number % 100) / 10];
- display_data[5] = digits[round(number % 10)];
- fill_display(6, 3);
- } else if (number >= 10000 && number <= 99999) {
- display_data[3] = digits[round(number / 10000)];
- display_data[4] = (digits[round(number / 1000 % 10)] & ~(1 << 7)); // Ставим точку после 2го разяряда (ex. 32.768)
- display_data[5] = digits[round(number % 1000 / 100)];
- display_data[6] = digits[round(number % 100 / 10)];
- display_data[7] = digits[round(number % 10)];
- fill_display(7, 1);
- } else if (number >= 100000 && number <= 999999) {
- display_data[3] = digits[round(number / 100000)];
- display_data[4] = digits[round(number / 10000 % 10)];
- display_data[5] = (digits[round(number / 1000 % 10)] & ~(1 << 7)); // Ставим точку после 3го разряда (ex. 327.680)
- display_data[6] = digits[round(number % 1000 / 100)];
- display_data[7] = digits[round(number % 100 / 10)];
- display_data[8] = digits[round(number % 10)];
- }
- }
- // Тетст всего экрана (все группы и сегменты)
- void test_display() {
- int i;
- for (i = 0; i < 14; i++) {
- display_data[i] = ~NC;
- }
- }
- // Основная программа
- 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);
- // Разрешание прерываний
- asm("SEI");
- // Вечный цикл
- while (1) {
- _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((unsigned int) mileage);
- print3digitDisplay(Speed);
- printLedScale(speed_scale);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment