Redfern_89

speedommetr.c

Dec 25th, 2017
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 15.19 KB | None | 0 0
  1. #include <avr/io.h>
  2. #include <util/delay.h>
  3. #include <EEPROM.h>
  4.  
  5. // Сигналы управления сдвиговыми регистрами
  6. #define RCLK 6    // Защелка
  7. #define SCLK 7    // Тактирование
  8. #define DATA 5    // Данные
  9.  
  10. // Тактовая частота процессора 16MHz
  11. #define F_CPU 16000000UL
  12.  
  13. #define BAUD 9600
  14. #define MYUBRR F_CPU / 16 / BAUD - 1
  15.  
  16.  
  17. // Макрос управления защелкой
  18. #define _74hc595_registerLatch(code) { PORTD &= ~(1 << RCLK); code; PORTD |= 1 << RCLK; }
  19. // Макрос управления сдвигом регистров
  20. #define _74hc595_registerShift() { PORTD &= ~(1 << SCLK); PORTD |= (1 << SCLK); }
  21.  
  22. // Данные о сегментах индикаторов
  23. const uint8_t digits[11] = {//        A
  24.   0b11000000,         //          #########
  25.   0b11111001,         //         #         #
  26.   0b10100100,         //       F #         # B
  27.   0b10110000,         //         #    G    #
  28.   0b10011001,         //          #########
  29.   0b10010010,         //         #         #
  30.   0b10000010,         //       E #         # C
  31.   0b11111000,         //         #         #
  32.   0b10000000,         //          #########
  33.   0b10010000,         //              D       ##
  34.   0b11111111          //                      dp
  35. };
  36.  
  37. // Данные о группах светодиодов (16 бит)
  38. const uint16_t groups[15] = {
  39. /* -------- 3 DIGIT DISPLAY -------- */
  40.   0b0000010000000000, // DIGIT 1      (0)
  41.   0b0000001000000000, // DIGIT 2      (1)
  42.   0b0000000100000000, // DIGIT 3      (2)
  43. /* -------- 6 DIGIT DISPLAY -------- */  
  44.   0b0000000010000000, // DIGIT 1      (3)
  45.   0b0000000001000000, // DIGIT 2      (4)
  46.   0b0000000000100000, // DIGIT 3      (5)
  47.   0b0000000000010000, // DIGIT 4      (6)
  48.   0b0000000000001000, // DIGIT 5      (7)
  49.   0b0000000000000100, // DIGIT 6      (8)
  50. /* --------  40 Leds Scale  -------- */
  51.   0b0010000000000000, // SCALE 1      (9)
  52.   0b0001000000000000, // SCALE 2      (10)
  53.   0b0000100000000000, // SCALE 3      (11)
  54.   0b0000000000000010, // SCALE 4      (12)
  55.   0b0000000000000001  // SCALE 5      (13)
  56. };
  57.  
  58. // Данные о светодиодах в шкале
  59. const uint8_t scale_leds[9] = {
  60.   0b11111111, // 0 LED's  
  61.   0b11111110, // 1 LED's
  62.   0b11111100, // 2 LED's
  63.   0b11111000, // 3 LED's
  64.   0b11110000, // 4 LED's
  65.   0b11100000, // 5 LED's
  66.   0b11000000, // 6 LED's
  67.   0b10000000, // 7 LED's
  68.   0b00000000  // 8 LED's
  69. };
  70.  
  71. unsigned int NC             = 0b11111111;       // Пустое значение
  72. unsigned int display_position       = 0;        // Текущее значение на экране / группа
  73. unsigned int CNT_Impulse        = 0;            // Колличество импульсов с датчика
  74. unsigned int CountImpulse       = 10;           // Точность точность измерений
  75. unsigned int CNT_OVF            = 0;            // Переполнения
  76. unsigned int TMP_CNT_OVF        = 0;            // Для сравнения с предыдущими переполнениями
  77. unsigned int TMP_TCNT           = 0;            // Запоминаем, сколько осталось до переполнения
  78. unsigned int ImpulsePerRotate       = 6;        // Колличество импульсов на 1 оборот колеса
  79. unsigned int CNT_Mileage_Impulse    = 0;        // Для подсчета импульсов пробега
  80. unsigned int total_scale_leds       = 40;       // Колличество светодиодов в шкале
  81. unsigned int leds_per_group     = 8;            // Колличество светодиодов на группу
  82. unsigned int MaximumSpeedCalc       = 200;      // Максимальная расчетная скорость
  83. unsigned int factorial          = 0;            // Факториал (сопоставление скорость/шкала)
  84. unsigned int speed_scale        = 0;            // Скорость на шкале светодиодов
  85. unsigned int display_groups_cnt     = 14;       // Колличество групп светодиодов
  86. unsigned int btn_tick_count     = 0;            // Пишем кол-во тиков программы для обработки долгого нажатия
  87. unsigned int btn_delay_titck        = 5;        // Кол-во тиков для долгого нажатия
  88. unsigned int btn_bounce_delay       = 50;       // Время дребезга контактов в мс
  89. unsigned int odometr_mode       = 0;            // Режим одометра. Общий/текущий
  90.  
  91. float LengthCircle          = 180.6128F;        // Размер колеса. R13 175/70
  92. float current_mileage           = 0.0F;         // Текущий пробег
  93. float total_milleage            = 0.0F;         // Общий пробег
  94. float ee_milleage           = 0.0F;             // пробег из EEPROM
  95. float Speed                 = 0.0F;             // Текущая скорость
  96. bool speed_flag             = false;            // Флаг измерения скорости
  97. bool ignition_flag          = false;            // флаг включенного зажигания
  98. bool eeprom_read_flag           = false;        // Флаг чтения из EEPROM
  99.  
  100. uint8_t display_data[14] = {NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC};
  101.  
  102. // Отправка данных по SPI
  103. void _74hc595_SPI_send(uint8_t data) {
  104.   for (uint8_t i = 0; i < 8; i++) {
  105.     byte value = !!(data & (1 << (7 - i)));
  106.     if (value) PORTD |= 1 << DATA; else PORTD &= ~(1 << DATA);
  107.     _74hc595_registerShift();
  108.   }  
  109. }
  110.  
  111. // Запись в регистры
  112. void _74hc595_registerWrite(uint16_t groups, uint8_t segments) {
  113.   // "Защелкиваем" данные в регистры
  114.   _74hc595_registerLatch({
  115.     _74hc595_SPI_send(groups >> 8);       // Сначала старший байт
  116.     _74hc595_SPI_send((groups) & 0xFF);   // Затем младший байт
  117.     _74hc595_SPI_send(segments);          // Теперь Один байт, отвечающий за сегменты
  118.   });
  119. }
  120.  
  121. // Описание таймера индикации
  122. ISR (TIMER1_OVF_vect) {
  123.   TCNT1 = 64456;                                    // Начинаем отсчет с 64456
  124.   display_position = (display_position + 1) % display_groups_cnt;           // Счиатем до 14 и сбрасываемся
  125.   _74hc595_registerWrite(groups[display_position], display_data[display_position]); // Отправляем в регистры текущие данные (Группа, сегменты)
  126. }
  127.  
  128. // Описание таймера подсчета импульсов
  129. ISR (TIMER0_OVF_vect) {
  130.    CNT_OVF++; // Прибавляем на 1 при каждом переполнении
  131. }
  132.  
  133. // Описание внешнего прерывания
  134. ISR (INT0_vect) {
  135.    // Считаем пробег
  136.    // Как только кол-во импульсов стало равно одному обороту колеса
  137.    // Прибавляем ктекущему пробегу длину колеса и преводим в километры
  138.    if (++CNT_Mileage_Impulse >= ImpulsePerRotate) {
  139.       current_mileage = current_mileage + (LengthCircle * 0.00001);
  140.       CNT_Mileage_Impulse = 0;
  141.    }
  142.    
  143.    // Счиатаем данные для расчета скорости
  144.    if (++CNT_Impulse >= CountImpulse) {
  145.       TMP_TCNT = TCNT0;     // Запоминаем, сколько осталось до переполнения
  146.       TMP_CNT_OVF = CNT_OVF;    // Запоминаем кол-во переполнений
  147.      
  148.       /* Обнуляем текущие счетчики */
  149.       CNT_OVF = 0;
  150.       TCNT0 = 0;
  151.       CNT_Impulse = 0;
  152.       speed_flag = true;
  153.    }
  154. }
  155.  
  156. ISR (INT1_vect) {
  157.    //current_mileage = 0.0F;
  158. }
  159.  
  160. // Заполнение участка массива индикации нулями
  161. void fill_display(int offset, int count) {
  162.    if (count >= offset) {
  163.       for (int i = offset; i < count; i++) {
  164.      display_data[i - offset] = NC;
  165.       }
  166.    }
  167. }
  168.  
  169. // Как я с этим заебался. Вывод данных на шкалу светодиодов
  170. void printLedScale(float leds) {
  171.    int led      = 0;
  172.    int unusedGroups = 0;
  173.    int groups       = 0;
  174.    int current      = 0;
  175.    
  176.    if (leds > total_scale_leds) leds = total_scale_leds;
  177.    groups = ceil(leds / leds_per_group);
  178.    if (leds > 0) {
  179.       for (int i = 0; i < groups; i++) {
  180.      current = i +1;
  181.      if (current |= groups) {
  182.         display_data[i +9] = scale_leds[leds_per_group -1];
  183.      } else {
  184.         led = leds - (leds_per_group * (groups - 1) ) -1;
  185.         display_data[i +9] = scale_leds[led];
  186.      }
  187.      unusedGroups = leds_per_group - groups;
  188.      
  189.      if (unusedGroups > 0) {
  190.         fill_display(groups +9, unusedGroups);
  191.      }
  192.       }
  193.    }
  194.    
  195. }
  196.  
  197. // Муторная процедура отображения данных на 3х цифровом индикаторе
  198. void print3digitDisplay(int number) {
  199.   if (number == 0) {
  200.     display_data[0] = (digits[0] & ~(1 << 7));
  201.     display_data[1] = digits[0];
  202.     display_data[2] = digits[0];
  203.   } else  if (number >= 1 && number <= 9) {
  204.     display_data[0] = digits[number];
  205.     fill_display(1, 2);
  206.   } else if (number >= 10 && number <= 99) {
  207.     display_data[0] = digits[round(number % 100) / 10];
  208.     display_data[1] = digits[round(number % 10)];
  209.     fill_display(2, 1);
  210.   } else if (number >= 100 && number <= 999) {
  211.     display_data[0] = digits[round(number / 100) % 10];
  212.     display_data[1] = digits[round(number % 100) / 10];
  213.     display_data[2] = digits[round(number % 10)];
  214.   }
  215. }
  216.  
  217. // Еще более мутная тема для 6ти цифр
  218. void print6digitDisplay(float number) {
  219.   if (number <= 9) {
  220.     display_data[3] = (digits[(int)floor(number)] & ~(1 << 7));
  221.     display_data[4] = digits[(int)floor(number * 10.0F) % 10];
  222.     fill_display(4, 3);
  223.   } else if (number >= 10 && number <= 99) {
  224.     display_data[3] = digits[(int)floor(number) % 100 / 10];
  225.     display_data[4] = digits[(int)floor(number) % 10] & ~(1 << 7);
  226.     display_data[5] = digits[(int)floor(number * 10.0F) % 10];
  227.     fill_display(3, 3);
  228.   } else if (number >= 100 && number <= 999) {
  229.     display_data[3] = digits[(int)floor(number) % 1000 / 100];
  230.     display_data[4] = digits[(int)floor(number) % 100 / 10];
  231.     display_data[5] = digits[(int)floor(number) % 10] & ~(1 << 7);
  232.     display_data[6] = digits[(int)floor(number * 10.0F) % 10];
  233.     fill_display(6, 2);
  234.   } else if (number >= 1000 && number <= 9999) {
  235.     display_data[3] = digits[(int)floor(number / 1000)];
  236.     display_data[4] = digits[(int)floor(number) / 100 % 10];
  237.     display_data[5] = digits[(int)floor(number) % 100 / 10];
  238.     display_data[6] = digits[(int)floor(number) % 10] & ~(1 << 7);
  239.     display_data[7] = digits[(int)floor(number * 10.0F) % 10];
  240.     fill_display(7, 1);
  241.   } else if (number >= 10000 && number <= 99999) {
  242.     display_data[3] = digits[(long int)floor(number) / 10000];
  243.     display_data[4] = digits[(long int)floor(number / 1000) % 10];
  244.     display_data[5] = digits[(long int)floor(number / 100) % 10];
  245.     display_data[6] = digits[(long int)floor(number / 10) % 10];
  246.     display_data[7] = digits[(long int)floor(number) % 10] & ~(1 << 7);
  247.     display_data[8] = digits[(long int)floor(number * 10.0F) % 10];
  248.   } else if (number >= 100000 && number <= 999999) {
  249.     display_data[3] = digits[(long int)floor(number) / 100000];
  250.     display_data[4] = digits[(long int)floor(number / 10000) % 10];
  251.     display_data[5] = digits[(long int)floor(number / 1000 )% 10] & ~(1 << 7); // Ставим точку после 3го разряда (ex. 327.680)
  252.     display_data[6] = digits[(long int)floor(number) % 1000 / 100];
  253.     display_data[7] = digits[(long int)floor(number) % 100 / 10];
  254.     display_data[8] = digits[(long int)floor(number) % 10];
  255.   }
  256. }
  257.  
  258. // Тетст всего экрана (все группы и сегменты)
  259. void test_display(bool null_byte = false) {
  260.   int i;
  261.  
  262.   for (i = 0; i < 14; i++) {
  263.     if (!null_byte) display_data[i] = ~NC;
  264.     else display_data[i] = NC;
  265.   }
  266. }
  267.  
  268. void USART_Transmit ( unsigned char data ) {
  269.    while (!(UCSR0A & (1 << UDRE0)));
  270.    UDR0 = data;
  271. }
  272.  
  273. void USART_SendString( char *StringPtr ) {
  274.    while (*StringPtr != 0x00) {
  275.       USART_Transmit(*StringPtr);
  276.       StringPtr++;
  277.    }
  278. }
  279.  
  280. float eeprom_read_float(int addr) {
  281.    byte raw[4];
  282.    for (byte i = 0; i < 4; i++) {
  283.       raw[i] = EEPROM.read(addr + i);
  284.    }
  285.    float &num = (float&)raw;
  286.    return num;
  287. }
  288.  
  289. void eeprom_write_float(int addr, float num) {
  290.    byte raw[4];
  291.    (float&)raw = num;
  292.    for (byte i = 0; i < 4; i++) EEPROM.write(addr + i, raw[i]);
  293. }
  294.  
  295. // Основная программа
  296. int main () {
  297.   // SPI - выводы для регистров
  298.   DDRD = 0b11100000;
  299.  
  300.   // Инициализация таймера 0 (Подсчет импульсов) 8bit
  301.   TIMSK0 = (1 << TOIE0);                             // Разрешаем таймер по переполнению
  302.   TCCR0B = (1 << CS12) | (0 << CS11) | (1 << CS10);  // Предделитель /1024
  303.   // 16000000 / 1024 = 15625
  304.  
  305.   // Таймер 1 (динамической индикации) 16 bit
  306.   TIMSK1 = (1 << TOIE1);
  307.   TCCR1B = (0 << CS12) | (1 << CS11) | (0 << CS10);  // Предделитель /8
  308.   TCNT1 = 64456;
  309.  
  310.   // Инициализация внешнего прерывания (на спад) на INT0
  311.   EICRA |= (1 << ISC01);
  312.   EIMSK |= (1 << INT0);
  313.  
  314.   // Инициализация внешнего прерывания (на спад) на INT1
  315.   EIMSK |= (1 << INT1);
  316.  
  317.   // Инициализация USART
  318.   UBRR0H = (unsigned char) (MYUBRR >> 8);
  319.   UBRR0L = (unsigned char) MYUBRR;
  320.   UCSR0B = (1 << RXEN0) | (1 << TXEN0);
  321.   UCSR0C = (1 << USBS0) | (1 << UCSZ00);
  322.  
  323.   current_mileage = eeprom_read_float(0);
  324.   unsigned long int i = 0;
  325.  
  326.   // Вечный цикл
  327.   while (1) {
  328.    
  329.     // проверка на включеннре зажигание
  330.     if (~PIND & (1 << 4)) {
  331.       ignition_flag = true;
  332.       if (!eeprom_read_flag) {
  333.      current_mileage = eeprom_read_float(0);
  334.      eeprom_read_flag = true;
  335.       }
  336.       asm("SEI");
  337.     } else {
  338.       test_display(true);
  339.       ignition_flag = false;
  340.       eeprom_read_flag = false;
  341.       eeprom_write_float(0, current_mileage);
  342.       asm("CLI");
  343.     }
  344.    
  345.  
  346.     if (ignition_flag) {  
  347.      // _delay_ms(500);
  348.       /*
  349.      Расчет скорости. пройденное расстояние делим Дельту времени и переводим в часы. Вот, как это сделалнно
  350.      
  351.         Таймер TIMER0 настроен на предделитель /1024, значит он будет рабоать на частоте 15.625KHz
  352.         Счиатем так: Колличество переполнений умножаем на разрядность таймера, прибавляем остатки от незаконченного
  353.         переполнения, делим на частоту таймера и переводим в часы. Это расчет дельты времени
  354.        
  355.       */
  356.       Speed = ((( CountImpulse / ImpulsePerRotate ) * LengthCircle) / (( TMP_CNT_OVF * 256 + TMP_TCNT) / 15625.0F)) * 0.036F;
  357.       factorial = (MaximumSpeedCalc / total_scale_leds);
  358.       speed_scale = floor(Speed / factorial);
  359.  
  360.       // Выводим текущие значения
  361.       print6digitDisplay((float) current_mileage);
  362.       print3digitDisplay(Speed);
  363.       printLedScale(speed_scale);
  364.      }
  365.      
  366.   }
  367.  
  368.   return 0;
  369. }
Advertisement
Add Comment
Please, Sign In to add comment