Страница 1 из 4
Atmega8: простенький секундомер
Добавлено: Чт июл 28, 2011 19:59:23
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 мс.
}
}
Re: Atmega8: простенький секундомер
Добавлено: Чт июл 28, 2011 20:13:27
Леонид Иванович
Как-то так:
Код: Выделить всё
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 мс.
}
}
Re: Atmega8: простенький секундомер
Добавлено: Чт июл 28, 2011 20:26:39
alexey6522
не получится, нет самого сдвига на следующий разряд
счет останавливается и индикатор тухнет
По сути эта строка должна так остаться
Код: Выделить всё
if (i==9)
//нужно как-то добавить сдвиг, а потом i=0;
i=0;
else i++;
Должен получиться цикл в цикле т.е. внешний цикл будет управлять счетом от 0 до 9, а внутри него проверка if (i==9) то переменную внешнего цикла обнулить, а к переменной внутреннего добавить +1
Вот как это сделать просто на языке прог, скажем в Delphi или С++ я знаю, а как используя сдвиговый регистр + МК и индикатор, не знаю
Re: Atmega8: простенький секундомер
Добавлено: Чт июл 28, 2011 21:12:22
Леонид Иванович
Можно и так, нет никакой разницы:
Код: Выделить всё
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 мс.
}
}
Re: Atmega8: простенький секундомер
Добавлено: Пт июл 29, 2011 21:09:41
alexey6522
А как записать число с плавающей запятой к примеру 9.9?
Re: Atmega8: простенький секундомер
Добавлено: Пт июл 29, 2011 21:33:48
Леонид Иванович
Запишите 99 и просто нарисуйте запятую в первом разряде.
Re: Atmega8: простенький секундомер
Добавлено: Сб июл 30, 2011 05:42:12
alexey6522
А если я захочу через COM или USB порт передать своему устройству значение 101.75? Мне придется разделить число на два значения 101 и 75, а потом в МК соединить их как 10175 и включить принудительно точку
Re: Atmega8: простенький секундомер
Добавлено: Сб июл 30, 2011 06:04:17
asteroid7
Необязательно делить. Передавайте текстом в ASCII.
101.75 = 0x31 0x30 0x31 0x2e 0x37 0x35
Re: Atmega8: простенький секундомер
Добавлено: Вс авг 14, 2011 17:42:56
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 мс.
}
}
Re: Atmega8: простенький секундомер
Добавлено: Вс авг 14, 2011 20:42:48
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 системе исчисления
Re: Atmega8: простенький секундомер
Добавлено: Пн авг 15, 2011 16:46:30
alexey6522
Ну что, добрых советов дождусь от кого-нибудь?!
Re: Atmega8: простенький секундомер
Добавлено: Вт авг 16, 2011 20:47:33
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 мс.
}
}
Re: Atmega8: простенький секундомер
Добавлено: Ср мар 28, 2012 15:48:01
Alexeyslav
Есть и более быстрые алгоритмы преобразования двоичного числа в двоично-десятичное, которое легко разобрать для вывода на индикатор. Операции с делением и вычислением остатка от деления хоть и наглядны но слишком ресурсоемки для такой простой операции.
Обычно такие преобразования называются как BIN2BCD
Re: Atmega8: простенький секундомер
Добавлено: Чт апр 19, 2012 23:36:03
Иринка
А на ассемблере ни у кого случайно нет программы для секундомера?
Re: Atmega8: простенький секундомер
Добавлено: Чт апр 19, 2012 23:54:36
Alexeyslav
"Случайно" нет. А разве есть сложности в написании? На примере часов например... вместо деления на секунды-минуты-часы, считайте только секунды большим числом в 32 бит, а затем BIN-2-BCD и на индикатор. или сразу считать каскадно единицы, десятки, сотни и т.д. в том числе и в минус, если это надо.
Re: Atmega8: простенький секундомер
Добавлено: Пт апр 20, 2012 06:35:44
BOB51
ммньдааа....
тут во многих темах народ возмущается - дескать зачем учить архаизмы вида I8080/Z80
а я удивляюсь - нафига для простенького секундомера atmega8, да еще со сдвиговыми регистрами?!!
ведь для вывода информации достаточно 8-разрядного сегментного порта и 4-5 линий для позиционных ключей...да и то только если дисплей на светодиодах (а не на современном, но более дорогом ЖКИ)
ну еще аппаратный приемопередатчик для внешнего обмена на выпендреж...
вполне пойдут attiny2313/pic16f628/pic18f1320/at89c205...

Re: Atmega8: простенький секундомер
Добавлено: Пт апр 20, 2012 16:21:44
Иринка
Alexeyslav, сложность в написании, конечно это очень сложно по причине того, что я не знаю ассемблер, поэтому и спросила вдруг у кого-нибудь завалялась программа и не жалко её.
Re: Atmega8: простенький секундомер
Добавлено: Пт апр 20, 2012 16:23:54
Иринка
BOB51, не нужен мне ни pic, ни attiny, мне именно под atmega8 надо, это же не я так хочу, а задание такое.
Re: Atmega8: простенький секундомер
Добавлено: Пт апр 20, 2012 22:18:12
Alexeyslav
Задание дают для того чтобы научится, и "не умею" тут не катит - оно как бы и является отправной точкой.
Прево-наперво, узнай как работает контроллер, ну... это можно выяснить из многочисленных книжек вроде "микроконтроллер - это просто".
Потом рисуется блок-схема устройства, после того как определишься с тем как собственно должен работать твой секундомер. Причем, довольно подробная. А затем понемногу определятся как раскрывать эти "кубики".
Собственно, программа что должна делать: по прерыванию от таймера организуется динамическая индикация(последовательно на индикатор выводишь содержимое определенных ячеек памяти: 8 ячеек на 8 знакомест), и заодно крутится счетчик с таким рассчетом чтобы насчитать количество прерываний на одну секунду - при достижении этого значения обнуляется и выполняется алгоритм прибавления 1 секунды к подсчитываемому времени и результат вносился в ячейки памяти из которых алгоритм динамической индикации выводит на индикатор.
Вобщем-то сложного тут нет, когда форум под рукой и даташит.
Re: Atmega8: простенький секундомер
Добавлено: Пт апр 20, 2012 23:41:35
ILYAUL
Alexeyslav писал(а):
.........Собственно, программа что должна делать: по прерыванию от таймера 17. 8-bit Timer/Counter2 with PWM and Asynchronous Operation
и даташит .
Извините , внес маленькую подсказку