Atmega8: простенький секундомер

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
alexey6522
Встал на лапы
Сообщения: 149
Зарегистрирован: Чт июл 28, 2011 18:12:28

Atmega8: простенький секундомер

Сообщение alexey6522 »

Всем привет! Решил освоить программирование для МК Atmega8 в составе с 74HC595 и 7-ми сегментным индикатором
Пользуюсь WainAVR и Proteus 7 pro. Есть наброска программы для секундомера, но она считает только от 0...9, а хочется хотя бы до 999999 без плавающей точки, в будущем хочу еще сделать и с точкой 00.0
Вопрос, как реализовать что бы счет продолжался до 99 на 2-х разрядном 7-ми сегментном индикаторе?

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

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

/*	  -A-
		F	B
		 -G-
		E	C
		 -D-	
*/
// составляем из сегментов цифры
#define	N0	(0x3F)		//0
#define	N1	(0x06)		//1
#define	N2	(0x5B)		//2
#define	N3	(0x4F)		//3
#define	N4	(0x66)		//4
#define	N5	(0x6D)		//5
#define	N6	(0x7D)		//6
#define	N7	(0x07)		//7
#define	N8	(0x7F)	    //8
#define	N9	(0x6F)		//9

unsigned char indikator[10]={N0, N1, N2, N3, N4, N5, N6, N7, N8, N9};

void export_data (unsigned int data)
{ 
  unsigned char i; //переменная i
  for (i=0;i<16;i++) {
    if ((data&0x8000)==0x00)
      PORTD&=~_BV(PD5); //Выставляем биты данных на PD5 (DATA канал)
    else 
	  PORTD|=_BV(PD5);
    PORTD|=_BV(PD6); //Импульс на SH_CP (запись)
    PORTD&=~_BV(PD6); 
    data=(data<<1);
  }  
 	PORTD|=_BV(PD7); //Импульс на ST_CP (защелка - вывод на индикатор записанных данных)
    PORTD&=~_BV(PD7);
}

int main(void)
{ 
  unsigned int DS=0;   //переменная DS 
  unsigned int i=0;    //переменная i
  PORTD=0x00; //Первоначально устанавливаем на всех выходах 0
  DDRD=0xff; //установить PD0-PD2 как выходы
  while (1)  //Бесконечный цикл
  {   
    DS=indikator[i]; //Закодированное число в 16hex системе исчисления
    export_data(DS);  //Отправляем данные на сдвиговый регистр			
	if (i==9) // Если i > 9 то обнуляем и пытаемся зажечь второй разряд
	  i=0;
	else i++;
      _delay_ms(300);  //пауза 300 мс.	
  }  
}

Вложения
sec.rar
исходник + схема в proteus7
(20.55 КБ) 507 скачиваний
Реклама
Аватара пользователя
Леонид Иванович
Друг Кота
Сообщения: 4779
Зарегистрирован: Сб апр 02, 2011 12:40:46
Откуда: Минск
Контактная информация:

Re: Atmega8: простенький секундомер

Сообщение Леонид Иванович »

Как-то так:

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

int main(void)
{
  unsigned int DS=0;   //переменная DS
  unsigned int i=0;    //переменная i
  PORTD=0x00; //Первоначально устанавливаем на всех выходах 0
  DDRD=0xff; //установить PD0-PD2 как выходы
  while (1)  //Бесконечный цикл
  {   
    DS=(indikator[i / 10] << 8) | indikator[i % 10]; //Закодированное число в 16hex системе исчисления
    export_data(DS);  //Отправляем данные на сдвиговый регистр         
   if (i==99) // Если i > 99 то обнуляем
     i=0;
   else i++;
      _delay_ms(300);  //пауза 300 мс.   
  } 
}
Реклама
alexey6522
Встал на лапы
Сообщения: 149
Зарегистрирован: Чт июл 28, 2011 18:12:28

Re: Atmega8: простенький секундомер

Сообщение alexey6522 »

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

if (i==99) // Если i > 99 то обнуляем
не получится, нет самого сдвига на следующий разряд
счет останавливается и индикатор тухнет
По сути эта строка должна так остаться

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

if (i==9) // Если i > 9 то обнуляем

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

	if (i==9)
         //нужно как-то добавить сдвиг, а потом i=0;
	  i=0;
	else i++;
Должен получиться цикл в цикле т.е. внешний цикл будет управлять счетом от 0 до 9, а внутри него проверка if (i==9) то переменную внешнего цикла обнулить, а к переменной внутреннего добавить +1
Вот как это сделать просто на языке прог, скажем в Delphi или С++ я знаю, а как используя сдвиговый регистр + МК и индикатор, не знаю
Аватара пользователя
Леонид Иванович
Друг Кота
Сообщения: 4779
Зарегистрирован: Сб апр 02, 2011 12:40:46
Откуда: Минск
Контактная информация:

Re: Atmega8: простенький секундомер

Сообщение Леонид Иванович »

Можно и так, нет никакой разницы:

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

int main(void)
{
  unsigned int DS=0;   //переменная DS
  unsigned int i=0, j=0;    //переменная i, j
  PORTD=0x00; //Первоначально устанавливаем на всех выходах 0
  DDRD=0xff; //установить PD0-PD2 как выходы
  while (1)  //Бесконечный цикл
  {   
    DS=(indikator[i] << 8) | indikator[j]; //Закодированное число в 16hex системе исчисления
    export_data(DS);  //Отправляем данные на сдвиговый регистр
   if (j==9)
  {
   j = 0;         
   if (i==9) // Если i > 9 то обнуляем
     i=0;
   else i++;
   }
   else j++;
      _delay_ms(300);  //пауза 300 мс.   
  }
}
Реклама
Эиком - электронные компоненты и радиодетали
alexey6522
Встал на лапы
Сообщения: 149
Зарегистрирован: Чт июл 28, 2011 18:12:28

Re: Atmega8: простенький секундомер

Сообщение alexey6522 »

А как записать число с плавающей запятой к примеру 9.9?
Реклама
Аватара пользователя
Леонид Иванович
Друг Кота
Сообщения: 4779
Зарегистрирован: Сб апр 02, 2011 12:40:46
Откуда: Минск
Контактная информация:

Re: Atmega8: простенький секундомер

Сообщение Леонид Иванович »

Запишите 99 и просто нарисуйте запятую в первом разряде.
Реклама
alexey6522
Встал на лапы
Сообщения: 149
Зарегистрирован: Чт июл 28, 2011 18:12:28

Re: Atmega8: простенький секундомер

Сообщение alexey6522 »

А если я захочу через COM или USB порт передать своему устройству значение 101.75? Мне придется разделить число на два значения 101 и 75, а потом в МК соединить их как 10175 и включить принудительно точку
Аватара пользователя
asteroid7
Опытный кот
Сообщения: 703
Зарегистрирован: Вс янв 18, 2009 21:12:49

Re: Atmega8: простенький секундомер

Сообщение asteroid7 »

Необязательно делить. Передавайте текстом в ASCII.
101.75 = 0x31 0x30 0x31 0x2e 0x37 0x35
alexey6522
Встал на лапы
Сообщения: 149
Зарегистрирован: Чт июл 28, 2011 18:12:28

Re: Atmega8: простенький секундомер

Сообщение alexey6522 »

Блин, а как добавить еще одни разряд для моего кода, что бы получить 999 и более объясните пожалуста как это сделать, по схеме-то мне все понятно, а вот с кодом проблемы?

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

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// составляем из сегментов цифры
#define	N0	(0x3F)		//0
#define	N1	(0x06)		//1
#define	N2	(0x5B)		//2
#define	N3	(0x4F)		//3
#define	N4	(0x66)		//4
#define	N5	(0x6D)		//5
#define	N6	(0x7D)		//6
#define	N7	(0x07)		//7
#define	N8	(0x7F)	    //8
#define	N9	(0x6F)		//9

unsigned char indikator[10]={N0, N1, N2, N3, N4, N5, N6, N7, N8, N9};
unsigned char y=0; //переменная y  

void export_data (unsigned int data)
{ 
  unsigned char i; //переменная i
  for (i=0;i<16;i++) {
    if ((data&0x8000)==0x00){
      PORTD&=~_BV(PD5); //Выставляем биты данных на PD5 (DATA канал)	  
	  }
    else {
	  PORTD|=_BV(PD5);
	  }
    PORTD|=_BV(PD6); //Импульс на SH_CP (запись)
    PORTD&=~_BV(PD6); 
    data<<=1;
  }  

 	PORTD|=_BV(PD7); //Импульс на ST_CP (защелка - вывод на индикатор записанных данных)
    PORTD&=~_BV(PD7);
}

int main(void)
{
  unsigned int DS=0;   //переменная DS
  unsigned int i=0, j=0;    //переменная i, j
  PORTD=0x00; //Первоначально устанавливаем на всех выходах 0
  DDRD=0xff; //установить PD0-PD2 как выходы
  DDRD&=~_BV(PD0); //устанавливаем PD0 как ввод 
  
  while (1)  //Бесконечный цикл
  {   
    DS=(indikator[i / 10] << 8) | indikator[i % 10]; //Закодированное число в 16hex системе исчисления
    export_data(DS);  //Отправляем данные на сдвиговый регистр         
   if (i==99) // Если i > 99 то обнуляем
     i=0;
   else i++;
      _delay_ms(300);  //пауза 300 мс.     
  }
}
Вложения
111.JPG
(113.08 КБ) 921 скачивание
alexey6522
Встал на лапы
Сообщения: 149
Зарегистрирован: Чт июл 28, 2011 18:12:28

Re: Atmega8: простенький секундомер

Сообщение alexey6522 »

Вот что я узнал, в схему добавил еще один регистр, четвертый и получил 32бита 32канала. Что в свою очередь == 4х разрядному индикатору
в коде изменил

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

void export_data (long int data)
{ 
  unsigned char i; //переменная i
  for (i=0;i<32;i++) {
    if ((data&0x80000000)==0x00){
иии теперь можно записать число от 0 до 9999
пример

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

   
DS=0x3F06667F;
export_data(DS);   //Отправляем данные на сдвиговый регистр
получим 8410, замечательно! Но как мне изменить мой счетчик, ни как не пойму что значит строка и как ее менять в соответствии с моими потребностями

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

DS=(indikator[i / 10] << 8) | indikator[i % 10]; //Закодированное число в 16hex системе исчисления
alexey6522
Встал на лапы
Сообщения: 149
Зарегистрирован: Чт июл 28, 2011 18:12:28

Re: Atmega8: простенький секундомер

Сообщение alexey6522 »

Ну что, добрых советов дождусь от кого-нибудь?!
alexey6522
Встал на лапы
Сообщения: 149
Зарегистрирован: Чт июл 28, 2011 18:12:28

Re: Atmega8: простенький секундомер

Сообщение alexey6522 »

Я чувствую себя новичком в С, мне правда стыдно.
Вот код счетчика, частично переделанный из 2-х разрядного в 4-х разрядный, в схеме 4 сдвиговых регистра, т.е. 32 канала и 32 бита, на участке кода
for (i=0;i<32;i++) {
if ((data&0x80000000)==0x00){
надеюсь сделал правильно, а как мне изменить следующий немаловажный участок отвечающий за сдвиг в случае если младший байт числа равен 9
DS=((indikator[i / 10] << 8 ) | indikator[i % 10]; эта часть кода предназначена для 2-х разрядного числа, как мне увеличить до 4-разрядного?
т.е. мне надо добавить еще сдвиг на 16 бит (2 байта) и получим что-то типа
DS=((indikator[i / 10] << 8 ) | (indikator[i / 10] << 8 ) | (indikator[i / 10] << 8 ) | indikator[i % 10]

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

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// составляем из сегментов цифры
#define   N0   (0x3F)      //0
#define   N1   (0x06)      //1
#define   N2   (0x5B)      //2
#define   N3   (0x4F)      //3
#define   N4   (0x66)      //4
#define   N5   (0x6D)      //5
#define   N6   (0x7D)      //6
#define   N7   (0x07)      //7
#define   N8   (0x7F)       //8
#define   N9   (0x6F)      //9

unsigned char indikator[10]={N0, N1, N2, N3, N4, N5, N6, N7, N8, N9};
unsigned char y=0; //переменная y   

void export_data (unsigned int data)
{
  unsigned char i; //переменная i
  for (i=0;i<32;i++) {
    if ((data&0x80000000)==0x00){
      PORTD&=~_BV(PD5); //Выставляем биты данных на PD5 (DATA канал)    
     }
    else {
     PORTD|=_BV(PD5);
     }
    PORTD|=_BV(PD6); //Импульс на SH_CP (запись)
    PORTD&=~_BV(PD6);
    data<<=1;
  } 

   PORTD|=_BV(PD7); //Импульс на ST_CP (защелка - вывод на индикатор записанных данных)
    PORTD&=~_BV(PD7);
}

int main(void)
{
  unsigned int DS=0;   //переменная DS
  unsigned int i=0, j=0;    //переменная i, j
  PORTD=0x00; //Первоначально устанавливаем на всех выходах 0
  DDRD=0xff; //установить PD0-PD2 как выходы

  while (1)  //Бесконечный цикл
   {   
      DS=((indikator[i / 10] << 8) | indikator[i % 10]; //Закодированное число в 16hex системе исчисления
      export_data(DS);   //Отправляем данные на сдвиговый регистр
      if (i==9999)  // Если i > 9999 то обнуляем
        i=0;
      else i++;
      _delay_ms(500);  //пауза 300 мс.
   }
}
Alexeyslav
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич
Контактная информация:

Re: Atmega8: простенький секундомер

Сообщение Alexeyslav »

Есть и более быстрые алгоритмы преобразования двоичного числа в двоично-десятичное, которое легко разобрать для вывода на индикатор. Операции с делением и вычислением остатка от деления хоть и наглядны но слишком ресурсоемки для такой простой операции.

Обычно такие преобразования называются как BIN2BCD
Иринка
Встал на лапы
Сообщения: 85
Зарегистрирован: Вт мар 27, 2012 16:07:25

Re: Atmega8: простенький секундомер

Сообщение Иринка »

А на ассемблере ни у кого случайно нет программы для секундомера?
Alexeyslav
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич
Контактная информация:

Re: Atmega8: простенький секундомер

Сообщение Alexeyslav »

"Случайно" нет. А разве есть сложности в написании? На примере часов например... вместо деления на секунды-минуты-часы, считайте только секунды большим числом в 32 бит, а затем BIN-2-BCD и на индикатор. или сразу считать каскадно единицы, десятки, сотни и т.д. в том числе и в минус, если это надо.
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15575
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Atmega8: простенький секундомер

Сообщение BOB51 »

ммньдааа....
тут во многих темах народ возмущается - дескать зачем учить архаизмы вида I8080/Z80 :)
а я удивляюсь - нафига для простенького секундомера atmega8, да еще со сдвиговыми регистрами?!! :shock:
ведь для вывода информации достаточно 8-разрядного сегментного порта и 4-5 линий для позиционных ключей...да и то только если дисплей на светодиодах (а не на современном, но более дорогом ЖКИ)
ну еще аппаратный приемопередатчик для внешнего обмена на выпендреж...
вполне пойдут attiny2313/pic16f628/pic18f1320/at89c205... :)))
Иринка
Встал на лапы
Сообщения: 85
Зарегистрирован: Вт мар 27, 2012 16:07:25

Re: Atmega8: простенький секундомер

Сообщение Иринка »

Alexeyslav, сложность в написании, конечно это очень сложно по причине того, что я не знаю ассемблер, поэтому и спросила вдруг у кого-нибудь завалялась программа и не жалко её.
Иринка
Встал на лапы
Сообщения: 85
Зарегистрирован: Вт мар 27, 2012 16:07:25

Re: Atmega8: простенький секундомер

Сообщение Иринка »

BOB51, не нужен мне ни pic, ни attiny, мне именно под atmega8 надо, это же не я так хочу, а задание такое.
Alexeyslav
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич
Контактная информация:

Re: Atmega8: простенький секундомер

Сообщение Alexeyslav »

Задание дают для того чтобы научится, и "не умею" тут не катит - оно как бы и является отправной точкой.

Прево-наперво, узнай как работает контроллер, ну... это можно выяснить из многочисленных книжек вроде "микроконтроллер - это просто".

Потом рисуется блок-схема устройства, после того как определишься с тем как собственно должен работать твой секундомер. Причем, довольно подробная. А затем понемногу определятся как раскрывать эти "кубики".

Собственно, программа что должна делать: по прерыванию от таймера организуется динамическая индикация(последовательно на индикатор выводишь содержимое определенных ячеек памяти: 8 ячеек на 8 знакомест), и заодно крутится счетчик с таким рассчетом чтобы насчитать количество прерываний на одну секунду - при достижении этого значения обнуляется и выполняется алгоритм прибавления 1 секунды к подсчитываемому времени и результат вносился в ячейки памяти из которых алгоритм динамической индикации выводит на индикатор.

Вобщем-то сложного тут нет, когда форум под рукой и даташит.
Аватара пользователя
ILYAUL
Держит паяльник хвостом
Сообщения: 906
Зарегистрирован: Ср мар 28, 2012 21:45:24
Откуда: ВО

Re: Atmega8: простенький секундомер

Сообщение ILYAUL »

Alexeyslav писал(а): .........Собственно, программа что должна делать: по прерыванию от таймера 17. 8-bit Timer/Counter2 with PWM and Asynchronous Operation

и даташит .
Извините , внес маленькую подсказку
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»