Тахометр и динамическая индикация

Обсуждаем контроллеры компании Atmel.
Ответить
Нашел транзистор. Понюхал.
Сообщения: 170
Зарегистрирован: Вс мар 30, 2014 21:41:24
Откуда: Украина

Сообщение sanyo.95 »

Здравствуйте! Хочу сделать тахометр для авто, но так как я новичок в программировании возникают проблемы с написанием кода. Знаю что готовых тахометров море, уверен что большинство из них я неоднократно пересматривал, пытаясь вникнуть в исходники. Но, как видите бесполезно, иначе я бы к вам не обращался. Для написания программы решил опираться на урок с сайта http://avr-start.ru/?p=883 о простом частотомере. Основная проблема в том, что в уроке(что выше), информация выводиться на LCD, а я собираюсь выводить на LED индикаторы. Основной вопрос: как организовать динамическую индикацию для вывода значения частоты?
Вот что - то написал - не работает(

Код: Выделить всё

#include <mega8.h>
#include <delay.h>
static flash unsigned char display[]=    // масив для индикатора
 {
  (0b11000000), // 0
  (0b11111001), // 1
  (0b10100100), // 2
  (0b10110000), // 3
  (0b10011001), // 4
  (0b10010010), // 5
  (0b10000010), // 6
  (0b11111000), // 7
  (0b10000000), // 8
  (0b10010000), // 9    
 };
 int f; 
interrupt [EXT_INT0] void ext_int0_isr(void) // внешние прерывания
 {
 f++;    
 }
 
 interrupt [TIM1_COMPA] void timer1_compa_isr(void)  // прерывания по таймеру раз в секунду
 {  
 f=0;
 }
 
 void disp(int Num)       // функция для вывода на индикатор
 {
  char Num0,Num1, Num2, Num3;
  Num1=Num2=Num0=0;
  while (Num >= 1000)
  {
  Num -= 1000;
  Num0++;
  }
  while (Num >= 100)
  {
  Num -= 100;
  Num1++;
  }
  while (Num >= 10)
  {
  Num -= 10;
  Num2++;
  }
  Num3 = Num;
    
  PORTC.0=1;
  PORTB=display[Num0];
  delay_ms(1);
  PORTC.0=0;
       
  PORTC.1=1;
  PORTB=display[Num1];
  delay_ms(1);
  PORTC.1=0;
       
  PORTC.2=1;
  PORTB=display[Num2];
  delay_ms(1);
  PORTC.2=0;
       
  PORTC.3=1;
  PORTB=display[Num3];
  delay_ms(1);
  PORTC.3=0;       
 }    

void main(void)
{ 
PORTB=0x00;
DDRB=0x7F; 
PORTC=0x00;
DDRC=0x0F;

TCCR0=0x00;
TCNT0=0x00;
TCCR1A=0x00;
TCCR1B=0x05;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x1E;
OCR1AL=0x85;
OCR1BH=0x00;
OCR1BL=0x00;

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Any change
// INT1: Off
GICR|=0x40;
MCUCR=0x01;
GIFR=0x40;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x10;

// Global enable interrupts
#asm("sei")

while (1)
      {
       disp(f);       // вызов функции
      }
}
Реклама
Друг Кота
Аватара пользователя
Сообщения: 4732
Зарегистрирован: Ср сен 18, 2013 10:08:26
Откуда: Санкт-Петербург

Сообщение Gisteresis »

Ну так блин, там урок есть для сегментников
http://avr-start.ru/?p=491

Сперва статическую посмотрите
http://avr-start.ru/?p=435
В динамике в принципе тоже самое, только нужно еще декады переключать через небольшие интервалы времени. Если жалко тратить столько ног МК то можно на регистрах делать.
Реклама
Нашел транзистор. Понюхал.
Сообщения: 170
Зарегистрирован: Вс мар 30, 2014 21:41:24
Откуда: Украина

Сообщение sanyo.95 »

Gisteresis спасибо огромное за ответ! Я с динамикой кое как разобрался, заработало - привожу код, может подскажете что где подправить чтобы "ровнее" был.
Вот теперь действительно интересно как через регистры сдвига все это запустить. Конкретно не понятно как это все в программе записать, второй день уже с этимы 595ми ковыряюсь и никак. Мне бы кода кусочек с примером, например, вывода числа на 4 разряда индикатора... Буду очень благодарен за любую помощь))

Код: Выделить всё

#include <mega8.h>
#include <delay.h>
static flash unsigned char display[]=    // масив для индикатора
 {
  (0b11000000), // 0
  (0b11111001), // 1
  (0b10100100), // 2
  (0b10110000), // 3
  (0b10011001), // 4
  (0b10010010), // 5
  (0b10000010), // 6
  (0b11111000), // 7
  (0b10000000), // 8
  (0b10010000), // 9    
 };
 int f, freq; 
interrupt [EXT_INT0] void ext_int0_isr(void) // внешние прерывания
 {
 f++;    
 }
 
 interrupt [TIM1_COMPA] void timer1_compa_isr(void)  // прерывания по таймеру раз в секунду
 {
 freq=f*60;  
 f=0;
 }
 
 void disp(int Num)       // функция для вывода на индикатор
 {
  char Num0,Num1, Num2, Num3;
  Num1=Num2=Num0=0;
  while (Num >= 1000)
  {
  Num -= 1000;
  Num0++;
  }
  while (Num >= 100)
  {
  Num -= 100;
  Num1++;
  }
  while (Num >= 10)
  {
  Num -= 10;
  Num2++;
  }
  Num3 = Num;
    
  PORTC.0=1;
  PORTB=display[Num0];
  delay_ms(1);
  PORTC.0=0;
       
  PORTC.1=1;
  PORTB=display[Num1];
  delay_ms(1);
  PORTC.1=0;
       
  PORTC.2=1;
  PORTB=display[Num2];
  delay_ms(1);
  PORTC.2=0;
       
  PORTC.3=1;
  PORTB=display[Num3];
  delay_ms(1);
  PORTC.3=0;       
 }    

void main(void)
{ 
PORTB=0x00;
DDRB=0x7F; 
PORTC=0x00;
DDRC=0x0F;

TCCR0=0x00;
TCNT0=0x00;
TCCR1A=0x00;
TCCR1B=0x05;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x0F;
OCR1AL=0x42;
OCR1BH=0x00;
OCR1BL=0x00;

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Any change
// INT1: Off
GICR|=0x40;
MCUCR=0x03;
GIFR=0x40;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x10;

// Global enable interrupts
#asm("sei")

while (1)
      {
       disp(freq);       // вызов функции
      }
}
Прорезались зубы
Аватара пользователя
Сообщения: 202
Зарегистрирован: Пн сен 26, 2011 13:48:25
Откуда: Харьков

Сообщение slavokhire5 »

Подправил Ваш код на свой вкус :) хотя там может быть что-то неправильно или "не православно"
Спойлер

Код: Выделить всё

#include <mega8.h>
#include <delay.h>
#include<inttypes.h>				// чтобы работало указание явной разрядности, см. далее
static flash unsigned char display[]=    // масив для индикатора
 {
	(0b11000000), // 0
	(0b11111001), // 1
	(0b10100100), // 2
	(0b10110000), // 3
	(0b10011001), // 4
	(0b10010010), // 5
	(0b10000010), // 6
	(0b11111000), // 7
	(0b10000000), // 8
	(0b10010000), // 9    
 };

// int в разных системах имеет разный вес. лучше явно указывать разрядность, требует подключения библиотеки
// переменные, которые изменяются в прерываниях, лучше обзывать volatile (почитайте про эту штуку)

volatile uint16_t f;			
volatile uint16_t freq; 

interrupt [EXT_INT0] void ext_int0_isr(void) // внешние прерывания
{
	f++;    
}
 
interrupt [TIM1_COMPA] void timer1_compa_isr(void)  // прерывания по таймеру раз в секунду
{
//freq=f*60;  
//f=0;

	// такая конструкция вероятно будет быстрее, чем умножение. а может и нет =)
	// и не переполнится ли у вас uint16_t? это ведь всего 65 * 1000
	freq = (f << 6) - (f << 2);
	f = 0;

}
 
 void disp(uint16_t Num)       // функция для вывода на индикатор
 {
	//char Num0,Num1, Num2, Num3;
	//Num1=Num2=Num0=0;
	
	uint8_t num[4] = {0,0,0,0};
	
	// "деление" красиво сделано
	while (Num >= 1000)
	{
		Num -= 1000;
		num[0] ++;
	}
	while (Num >= 100)
	{
		Num -= 100;
		num[1] ++;
	}
	while (Num >= 10)
	{
		Num -= 10;
		num[2] ++;
	}
	num[3] = Num;
    
	/*PORTC.0=1;
	PORTB=display[Num0];
	delay_ms(1);
	PORTC.0=0;
	   
	PORTC.1=1;
	PORTB=display[Num1];
	delay_ms(1);
	PORTC.1=0;
	   
	PORTC.2=1;
	PORTB=display[Num2];
	delay_ms(1);
	PORTC.2=0;
	   
	PORTC.3=1;
	PORTB=display[Num3];
	delay_ms(1);
	PORTC.3=0;  */
	
	// такая конструкция должна меньше места занимать, но проиграет в быстродействии Вашей
	for (uint8_t i = 0; i < 4; i++)
	{
		PORTC |= (1 << i);
		PORTB = display[num[i]];
		PORTC &= ~(1 << i);
		delay_ms(1);
	}

     
 }    

void main(void)
{ 
	PORTB=0x00;
	DDRB=0x7F; 
	PORTC=0x00;
	DDRC=0x0F;

	TCCR0=0x00;
	TCNT0=0x00;
	TCCR1A=0x00;
	//TCCR1B=0x05; - ни о чем не говорит. конструкция ниже занимает столько же места в памяти,
	// но более наглядна

	TCCR1B = (1 << CS12) | (1 << CS10);
	
	// и так далее
	ICR1H=0x00;
	ICR1L=0x00;
	OCR1AH=0x0F;
	OCR1AL=0x42;
	OCR1BH=0x00;
	OCR1BL=0x00;

	// External Interrupt(s) initialization
	// INT0: On
	// INT0 Mode: Any change
	// INT1: Off
	GICR|=0x40;
	MCUCR=0x03;
	GIFR=0x40;

	// Timer(s)/Counter(s) Interrupt(s) initialization
	TIMSK=0x10;

	// Global enable interrupts
	#asm("sei")

	while (1)
	{
		disp(freq);       // вызов функции
	}
}
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Аватара пользователя
Сообщения: 4732
Зарегистрирован: Ср сен 18, 2013 10:08:26
Откуда: Санкт-Петербург

Сообщение Gisteresis »

Не вопрос, сейчас загуглю! :)))

http://radioparty.ru/index.php/device-p ... on-74hc164
Тут сделано на 164ом регистре, статическая индикация.
http://radioparty.ru/index.php/prog-avr ... on-74hc595
Тут на 595ом, так же статическая.
Чтобы сделать динамическую достаточно минимум 2х регистров. В первый регистр нужно писать код для декады индикатора, а во второй писать "адрес", то есть сигнал на зажигание декады. При динамической конечно лучше использовать 595й так как он имеет промежуточный бефер "защелку".
Вот примерно так:
http://chipenable.ru/index.php/programm ... tsiya.html
http://radioparty.ru/index.php/device-p ... vensegment
Текст не читал, но вижу что оно.
Опять такие тоже самое описано тут:
http://avr-start.ru/?p=491

Можно сделать и покруче. Есть драйвера семисегментных индикаторов, например MAX7219 и MAX7221
http://mcucpu.ru/index.php/project2/ind ... 60-max7219
http://pro-diod.ru/electronica/max7219- ... kacii.html
К одной микрухе можно подключить до 8ми декад.

Я думаю достаточно информации чтобы начать лепить индикацию самому?

Теория и так вроде нормально расписана.
Основные моменты: Из числа выделяем декаду для отображения. Посылаем ее в функцию отображения. Она зажигает соответствующие сегменты. Если нужна динамическая, то зажигаем поочередно по одной цифре в цикле или например в прерывании таймера.

Конкретно про 595ый и 164ый
Это сдвиговые регистры. В них информация поступает последовательно а выходит параллельно.
Последовательно мы загружаем в них через МК, там есть вывод такта, вывод данных, в 595ом есть вывод защелки.
Выходят данные уже на сегменты индикатора.
Вот например
http://radioparty.ru/index.php/prog-avr ... on-74hc595

Код там в принципе одинаковый. Разница не большая. Кто то оформляет в отдельные функции кто то нет.
Реклама
Ответить

Вернуться в «AVR»