Страница 1 из 1

Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 13:11:18
binarick
Рыл на форуме долго и упорно и не нашёл по моему вопросу.

В общем задача банальная: засветить 3х символьный 7сегментник
Но ! Беда в том, что во всех примерах на форуме он занимает целый порт.
У меня атмега8 + кварц(заняты PB6 и PB7) + кнопки на прерываниях(int0 занят), отсюда я не могу использовать порт весь целиком
а во всех программах используют чтото подобное:

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

while (1)
      {
        switch (cur_dig)
        {
            case 0:{digit3=0; digit1=1; break;};  //подаём питание на разряд 3
            case 1:{digit1=0; digit2=1; break;};  //подаём питание на разряд 2
            case 2:{digit2=0; digit3=1; break;};  //подаём питание на разряд 1
        }
        PORTB=digits[digit_out[cur_dig]];    //выводим с каждым срабатыванием таймера число с масива в порт В, но не для всех разрядов сразу
        cur_dig++;                           //с каждым срабатыванием таймера, увеличиваем переменную cur_dig на 1
        if(cur_dig==3) cur_dig=0;            //если cur_dig = 3 обнуляем
а именно PORTB=digits[digit_out[cur_dig]]; что не возможно для меня.

так вот прошу подсказки или примера кода (если возможно) как можно это обойти.
здорово бы было если порты задать через #define, но как их потом перебирать и присваивать ума не приложу

Спасибо за ваше время и ответы

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 13:54:10
Gudd-Head
Ну так если у вас порт будет раскидан по разным ногам, тогда надо всё делать побитово.
Намного проще будет, если вы наскребёте две тетрады (пины 0...3 и/или 4...7 одного порта).

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 13:57:01
B@R5uk
Решение без модификации схемы заключается в том, чтобы выводить данные на свободные пины нескольких портов.

Решение с добавлением внешнего элемента заключается в том, чтобы выводить данные через два пина ( ! ) с помощью SPI на сдвиговый регистр. Это решение так же хорошо тем, что с тремя сдвиговыми регистрами можно сделать статическую, а не динамическую индикацию, а модуль индикации будет внешним, к которому будут вести всего 4 провода (2 питания, клок и данные).

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 13:58:54
binarick
могу освободить любые порты кроме тех которые я перечислил это кварц и любое прерывание int0 либо int1

я понимаю что побитно. но как написать красивый алгоритм типа как в примере, а не городить повторяющиеся и почти аналогичные куски кода. и желательно с дефайнами
Решение с добавлением внешнего элемента заключается в том, чтобы выводить данные через два пина с помощью SPI на сдвиговый регистр.
пока не хотелось бы так делать, свободных портов много

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 14:03:18
B@R5uk
Ну, перекиньте тогда два старших бита порта B на порт D.

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 14:04:29
binarick
B@R5uk писал(а):Ну, перекиньте тогда два старших бита порта B на порт D.
вобщем вопрос в том и заключается как это сделать наименее громоздко ?

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 14:05:06
Gudd-Head
B@R5uk писал(а):Это решение так же хорошо тем, что с тремя сдвиговыми регистрами можно сделать статическую, а не динамическую индикацию
Особенно это решение "хорошо" если сегментник заточен под динамическую индикацию, и у него просто не выведены все ноги :)))

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 14:13:24
B@R5uk
Gudd-Head писал(а):если сегментник заточен под динамическую индикацию
Вы имели в виду под статическую? А это и не важно. В регистр можно писать все данные: и сигналы на аноды, и сигналы на катоды. Разница будет только в программном коде, а коммутация останется прежней.
binarick писал(а):вопрос в том и заключается как это сделать наименее громоздко ?
Вообще так можно делать. Вместо

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

    PORTB = digits [ digit_out [cur_dig] ];
написать

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

    uint8_t tmpB = digits [ digit_out [cur_dig] ];
    uint8_t tmpD = digits [ digit_out [cur_dig] ];
    tmpB >>= 2;
    tmpD <<= 6;
    uint8_t PDov = PORTD;
    PDov &= 0x3F;
    tmpD |= PDov;
    PORTB = tmpB;
    PORTD = tmpD;
На ассемблере это бы красивее выглядело. Данные, которые планировалось разместить в PB0...PB7 теперь выводятся в PD6,PD7,PB0...PB5 соответственно.

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 14:17:31
binarick
спасибо буду пробовать. Нет ассемблер мне не подходит :) не грамотен я в нём совсем

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 14:20:18
B@R5uk
А у меня си в АВР-студии на работает, поэтому я грамотен. Изображение Вы в какой среде кодите?

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 14:21:43
binarick
B@R5uk писал(а):А у меня си в АВР-студии на работает, поэтому я грамотен. Изображение Вы в какой среде кодите?
CodeVision 3.12

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 14:27:11
B@R5uk
Если просто два старших бита с порта B на порт D перекинуть, то будет ещё проще:

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

    uint8_t tmp = digits [ digit_out [cur_dig] ];
    uint8_t PDov = PORTD;
    PDov &= 0x3F;
    PORTB = tmp;
    tmp &= 0xC0;
    tmp |= PDov;
    PORTD = tmp;
Тут, как и в предыдущем случае есть маленькая неприятность: модификация портов не является атомарной, поэтому, если в где-то в прерывании модифицируется порт D, и эта модификация попадёт между чтением порта D и его записью предложенным мною кодом, то модификация будет перезаписана старым значением. Так что тут либо следить надо, либо отключить прерывания на время вывода данных.

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 14:49:43
binarick
B@R5uk писал(а): Тут, как и в предыдущем случае есть маленькая неприятность: модификация портов не является атомарной, поэтому, если в где-то в прерывании модифицируется порт D, и эта модификация попадёт между чтением порта D и его записью предложенным мною кодом, то модификация будет перезаписана старым значением. Так что тут либо следить надо, либо отключить прерывания на время вывода данных.
сейчас не уверен но порт D используется, попробую, что получится
схемку переделал теперь как-то так будет:
Изображение

Re: Семисегментник + Atmega8

Добавлено: Вт июн 09, 2015 16:20:11
B@R5uk
Я так понимаю, на выход порт D используется всё для того же индикатора и в той же процедуре. А пины-входы порта D без подтяжки. Есть смысл заранее подготовить и реализовать вывод всех выходных пинов одним махом.

Чтобы индикатор светился на входа ABCDEFG должен быть высокий уровень, а на входах 1234 — низкий, или наоборот? Кстати, можно модель индикатора, а то меня цифровое отображение данных тоже интересует.

Re: Семисегментник + Atmega8

Добавлено: Ср июн 10, 2015 05:52:31
binarick
второй алгоритм работает!

Спасибо огромное

осталось мне понять как он работает :)))

С подтяжками не разбирался ещё только в протеусе собрал. Сейчас буду схемку приводить в рабочее состояние
например такой будет C-563G-12
http://www.paralight.us/uploads/pdf/C-563G%20A1.pdf

Re: Семисегментник + Atmega8

Добавлено: Ср июл 01, 2015 12:51:10
binarick
Ребят помогите ошибку найти

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

//------------------
void recoding(int indication) {       //функция для перекодировки из hex в dec

    digit_out[0]=indication%10; //Делим на 10 остаток в масив 1-разряд
    indication=indication/10;   //Оставляем 2 разряда
    digit_out[1]=indication%10; //Делим на 10 остаток в масив 2-разряд
    digit_out[2]=indication/10; //Делим на 10 целое число в масив 3-разряд
}

//-----------------

while (1)
      {
        TimeData= 123;
            recoding(TimeData);
            //PORTB=0b000000; //убираем тень
            //PORTD=0b00000000;
            for (cur_dig=0; cur_dig<2 ;cur_dig++)
            {
                if      (cur_dig ==0) {digit3= 1; digit1=0;}
                else if (cur_dig ==1) {digit1= 1; digit2=0;}
                else if (cur_dig ==2) {digit2= 1; digit3=0;}

                tmp = digits [ digit_out [cur_dig] ];
                PDov = PORTD;
                PDov &= 0b111111; //0x3F;
                PORTB = tmp;
                tmp &= 0b11000000; //0xC0;
                tmp |= PDov;
                PORTD = tmp;

        }

      }
на экране имею:
Изображение

а должно быть "123"

и можно как-то убрать цикл типа for (cur_dig=0; cur_dig<2 ;cur_dig++) и за раз выводить 3,2 и 1 разряды.... думаю с ним связана ошибка но додумать не могу :(

на нравится мне digit3= 1; не понимаю зачем их гасить но если не гасить то вообще ерунда какаято
Спасибо

Re: Семисегментник + Atmega8

Добавлено: Ср июл 01, 2015 17:35:32
dr.doc
if (cur_dig ==0) {digit3= 1; digit1=0;}
else if (cur_dig ==1) {digit1= 1; digit2=0;}
else if (cur_dig ==2) {digit2= 1; digit3=0;}
Сам пишу на ассемблере, но, сдается мне, что в данном коде выводится цифра на 2 общих катода (анода) при любом значении cur_dig...