Страница 1 из 1
CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Сб ноя 29, 2014 15:28:27
Technik_91
Всем привет! Уже неделю не могу победить MAX7219, подключенный к Atmega8. Знаю, может все и просто, ошибки у меня ламерские, но и познания в программировании не особо большие, желание есть, а вот опыта не хватает

По гуглу перепробовал много вариантов, ни один не заработал, подскажите что не так в моей программе. Не проходит даже инициализация макса. Вот листинг CodeVisionAVR:
Код: Выделить всё
#include <mega8.h>
#define SPI_PORTX PORTC
#define SPI_DDRX DDRC
#define SPI_MISO 2
#define SPI_MOSI 5
#define SPI_SCK 4
#define SPI_SS 3
/*инициализация SPI модуля в режиме master*/
void SPI_Init(void)
{
/*настройка портов ввода-вывода
все выводы, кроме MISO выходы*/
SPI_DDRX |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(0<<SPI_MISO);
SPI_PORTX |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(1<<SPI_MISO);
SPI_PORTX |= (1<<SPI_SS);
SPI_PORTX &= ~(1<<SPI_SCK);
SPI_PORTX &= ~(1<<SPI_MOSI);
}
void SPI_WriteData(char adres, char data)
{ char i=16;
int tmp=adres;
tmp = (tmp<<8)|data;
SPI_PORTX &= ~(1<<SPI_SS);
{while(i>0)
{
SPI_PORTX &= ~(1<<SPI_SCK);
SPI_PORTX.SPI_MOSI=((tmp & (1<<(i-1))) != 0 );
SPI_PORTX |= (1<<SPI_SCK);
i--;
}
}
SPI_PORTX &= ~(1<<SPI_SCK);
SPI_PORTX |= (1<<SPI_SS);
SPI_PORTX &= ~(1<<SPI_MOSI);
}
char count=8;
void main(void)
{
SPI_Init();
SPI_WriteData(0xF,0x0);
SPI_WriteData(0xC,0x0);
SPI_WriteData(0xB,0x7);
SPI_WriteData(0x9,0x0);
SPI_WriteData(0xA,0xF);
{while(count>0)
{
SPI_WriteData(count,0x0);
count--;
}
}
while (1)
{
}
}
Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Сб ноя 29, 2014 20:20:14
Halex
Во-первых, приучитесь ПРАВИЛЬНОписанию шестнадцатиричных чисел, чтобы окружающих не коробило. А во-вторых, тем более, что начинающий, снабжать свои недельные потуги комментариями, чтобы остальным не ломать моСК над Вашим кодом. В свете этих двух замечаний приведу кусочек вашего кода так, как он должен был БЫ выглядеть в нормальном изложении, а уж что там не так - догадаетесь сами. Для того и комментарии пишутся.
Код: Выделить всё
SPI_Init();
SPI_WriteData(0x0F,0x00); // Отключить тестовый режим
SPI_WriteData(0x0C,0x00); // Выключить индикацию (!!!)
SPI_WriteData(0x0B,0x07); // Установить количество подключенных индикаторов (разрядов) - 8
SPI_WriteData(0x09,0x00); // Отключить встроенный декодер BCD для всех разрядов (!!!)
SPI_WriteData(0x0A,0x0F); // Установить максимальную яркость индикации
Вот из кода в таком виде, как говорят,
даже ежу всё становится понятно, а уж нам пушистым и хвостатым и подавно.
Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Сб ноя 29, 2014 21:42:56
COKPOWEHEU
На самом деле 0xF тоже пишут, это не ошибка и не плохое форматирование. Такое встречается, например, в библиотеке vusb.
Но мне тоже кажется логичным дополнять двоичную запись до размера переменной.
На счет комментариев - полностью согласен, они нужны, особенно когда "программист" сам не знает что и для чего делает.
Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Вс ноя 30, 2014 07:58:31
Halex
COKPOWEHEU писал(а):На самом деле 0xF тоже пишут, это не ошибка и не плохое форматирование.
Компилятор, да и то не всякий, такое проглотит, а вот разбор чужих полетов уже затрудняется. МоСК уже приучЁн разворачивать в уме байты из шестнадцатеричной в двоичную форму. Когда глаза чего-то не находят, соответственно и моСК тормозит. Напишите в столбик одно под другим несколько байт в шестнадцатеричной форме, причем вперемешку -
"детям до шестнадцати и старше" (ИМХО - часть без старшего незначащего нуля). Гарантирую, глаза сами будут выхватывать последние и тормозить на них - а не АшиПка ли?. Аналогично и с двухбайтовыми long.
COKPOWEHEU писал(а):Но мне тоже кажется логичным дополнять двоичную запись до размера переменной.
Не в обиду Вам, но повторюсь -
шестнадцатеричную. В двоичной форме запись начинается с
0b и далее единичками/нулями побитно.
ПЫСЫ Я не придираюсь, просто мы так совсем топикстартера с пути истинного сбить можем. А у него и так косяк на косяке. Мало того, что при инициализации MAX-а он его просто вырубил, так еще и в майне "приколов" хватает. Первый
while пролетит за микросекунды и благополучно уйдет в бесконечный пустой
while(1).
Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Вс ноя 30, 2014 10:37:30
Technik_91
В том то и дело, что max не вырубается, как горели все индикаторы, так и горят. Указывать на мои ошибки правильно, но дельного совета так никто и не дал.

Так в чем мои ошибки? Я поправил код, как вы сказали, спасибо. Но он как был не рабочим, так таким и остается.
Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Вс ноя 30, 2014 12:45:52
COKPOWEHEU
Не в обиду Вам, но повторюсь - шестнадцатеричную
Двоичную, восмеричную, шестнадцатеричную. Любую, привязанную к железу.
Когда глаза чего-то не находят, соответственно и моСК тормозит.
Ну, запись в столбик аналогичных десятичных чисел проблемы не вызваает. Тут уж кому как удобнее. Неправильным форматированием это считать не стоит.
В двоичной форме запись начинается с 0b и далее единичками/нулями побитно.
Запись 0b111 вполне проглатывается компилятором и может быть удобна для задания нескольких связанных битов.
SPI_PORTX &= ~(1<<SPI_SCK);
SPI_PORTX.SPI_MOSI=((tmp & (1<<(i-1))) != 0 );
SPI_PORTX |= (1<<SPI_SCK);
А тут случайно не надо добавить задержку? Или, например, воспользоваться аппаратным модулем? И while'ы заменить на обычные for.
Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Вс ноя 30, 2014 13:42:11
Technik_91
задержки по 10мс добавил, ничего не поменялось. Аппаратным модулем тоже пробовал, не заработало, а когда пошагово в авр студии выпонял программу, то у PORTC никакие биты не менялись, в отличие от своего варианта. По этому на нем и остановился. А насчет задержек - max вроде до 10 Мгц работает, а мега на 8. Должно же работать...
Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Вс ноя 30, 2014 15:25:15
COKPOWEHEU
Аппаратным модулем тоже пробовал, не заработало, а когда пошагово в авр студии выпонял программу, то у PORTC никакие биты не менялись, в отличие от своего варианта
Пробовали аппаратным модулем, выведенным на PB2-PB5 управлять устройством, висящим на PORTC?
void SPI_WriteData(char adres, char data)
Не проверяли в протеусе работу самой функции?
Я поправил код, как вы сказали
Хорошо бы его увидеть. И схему заодно, а лучше модель в протеусе, благо там все это есть.
Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Вс ноя 30, 2014 16:38:48
Technik_91
Когда подключал к аппаратному модулю - подключал к аппаратным выводам SPI. Тему можно закрывать, я разобрался. Как тут справедливо заметили, надо было посмотреть как я конфигурирую MAX.
SPI_WriteData(0x0C,0x00); // Выключить индикацию (!!!) - отключает индикацию, просто я инициализацию с сайта посмотрел, и был уверен что она правильная. А стоило посмотреть в даташит. А горели все сегменты потому что у меня семисегментник с общим анодом, соответственно когда микросхема ничего не выводила - выводы были притянуты к земле - все сегменты горели. Спасибо что помогли

Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Вс ноя 30, 2014 19:16:48
Halex
Technik_91 писал(а): А горели все сегменты потому что у меня семисегментник с общим анодом
"Лечится" и такое. К выводам сегментов MAX-a подключаются общие аноды индикатора, а к выводам разрядов MAX-а - сегменты индикатора. Вот тогда действительно внутренний дешифратор надо обязательно отключить, а данные перед выводом транспонировать.
Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Вт дек 02, 2014 19:55:58
Technik_91
Так и сделал. Спасибо за подсказки. Все работает, только не удобно, все таки с общим катодом было бы удобнее

Re: CodeVisionAVR+MAX7219 подскажите с программой
Добавлено: Ср ноя 18, 2015 09:02:32
Romul
Программа то кстати рабочая. Единственная оплошность при инициализации. Вместо
Код: Выделить всё
SPI_WriteData(0x0C,0x00); // Выключить индикацию
нужно писать
Код: Выделить всё
SPI_WriteData(0x0C,0x01); // Включить индикацию
А если еще включить декодер
Код: Выделить всё
SPI_WriteData(0x09,0xFF); // Включить встроенный декодер BCD для всех разрядов (!!!)
то информация на индикаторе будет отображаться в явном виде. То есть передали
значит в первом разряде единица и отобразится. И таблицу перекодировки писать не нужно. В качестве примера эта же, но уже рабочая программа для тестирования китайского восьмиразрядного индикатора.
Код: Выделить всё
#include <mega2560.h>
#include <delay.h>
#define SPI_PORTX PORTB
#define SPI_DDRX DDRB
#define SPI_MISO 4
#define SPI_MOSI 7
#define SPI_SCK 5
#define SPI_SS 6
unsigned char count = 0;
unsigned int dig = 0;
/*инициализация SPI модуля в режиме master*/
void SPI_Init(void)
{
/*настройка портов ввода-вывода
все выводы, кроме MISO выходы*/
SPI_DDRX |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(0<<SPI_MISO);
SPI_PORTX |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(1<<SPI_MISO);
SPI_PORTX |= (1<<SPI_SS);
SPI_PORTX &= ~(1<<SPI_SCK);
SPI_PORTX &= ~(1<<SPI_MOSI);
}
void SPI_WriteData(char adres, char data)
{
char i=16;
int tmp=adres;
tmp = (tmp<<8)|data;
SPI_PORTX &= ~(1<<SPI_SS);
{while(i>0)
{
PORTB &= ~(1<<SPI_SCK);
PORTB =(((tmp & (1<<(i-1))) != 0 )<<SPI_MOSI);
PORTB |= (1<<SPI_SCK);
i--;
}
}
PORTB &= ~(1<<SPI_SCK);
PORTB |= (1<<SPI_SS);
PORTB &= ~(1<<SPI_MOSI);
}
void ind(unsigned int c )
{
SPI_WriteData(0B00000001, c% 10);
SPI_WriteData(0B00000010, c% 100 / 10);
SPI_WriteData(0B00000011, c% 1000 / 100);
SPI_WriteData(0B00000100, c% 10000 / 1000);
SPI_WriteData(0B00000101, c% 100000 / 10000);
SPI_WriteData(0B00000110,0B00000000); // c% 1000000 / 100000);
SPI_WriteData(0B00000111,0B00000000); // c% 10000000 / 1000000);
SPI_WriteData(0B00001000,0B00000000); // c% 100000000 / 10000000);
}
void main(void)
{
SPI_Init();
delay_us(1000);
SPI_WriteData(0b00001111,0b00000000); // Тест дисплея
delay_us(1000);
SPI_WriteData(0b00001011,0b00000111); // Кол-во символов
delay_us(1000);
SPI_WriteData(0b00001001,0b11111111); // Дешифраторы включены для всех разрядов
delay_us(1000);
SPI_WriteData(0b00001010,0b00000011); // Интенсивность свечения средняя
delay_us(1000);
SPI_WriteData(0b00001100,0b00000001); // Выход из сна
delay_us(1000);
while (1)
{
if (count++>100) count=0,dig++;
if (dig>64000) dig=0;
ind(dig);
}
}