Добавлено after 4 hours 25 minutes 39 seconds: serg_svd, Дело было в SSPSTAT. Подпилил ваш драйвер ssd1306 под свой i2c, закинул в отладочную плату, красота.
Добавлено after 5 minutes 32 seconds: хотя у меня подтяжка на плате через резисторы 10к к +5 В и все норм работает и раньше работало)
хотя у меня подтяжка на плате через резисторы 10к к +5 В и все норм работает и раньше работало)
Спасибо за помощь! У меня тоже резисторы 10кОм были, но я поверх них запаял еще по 10к. В итоге стало 5к подтягивающие. Просто думал в них дело... Схему на плату ssd1306 я только огрызок нашел, но в ней тоже подтягивающие по питанию после стабилизатора подключены. На своей плате я тщательно все прозвонил. Не думаю, что китайцы столько модификаций плат лепят.
_________________ "Чтобы правильно задать вопрос, нужно знать бо́льшую часть ответа." Ро́берт Ше́кли Я правильных ответов знаю мало, поэтому не стесняюсь и много спрашиваю.
Кстати попробуйте увеличить частоту i2c. Для 128х64 на частоте 100кгц медленный вывод шрифтом 5х8. Чтоб заполнить весь экран символами уходит гдето 0.5 секунды.
Игрался с частотой. Насколько знаю, предел 400 кГц. Но даже при такой частоте видно, как заполняется дисплей. Для больших объемов выводимой информации я предпочитаю вначале гасить индикатор после очистки, выводить информацию и затем включать его. PS. я такие дисплеи, хоть и имею несколько штук в наличии, но в своих конструкциях так и не применил. Хотя для простого применнения можно обойтись и без буфера, но, по-хорошему, все-же лучше с буфером. Но для этого требуются жирные контролллеры с минимум 2 кБ памяти.
_________________ "Чтобы правильно задать вопрос, нужно знать бо́льшую часть ответа." Ро́берт Ше́кли Я правильных ответов знаю мало, поэтому не стесняюсь и много спрашиваю.
Здравствуйте! Нет ли у кого примера динамической индикации на PIC+74HC595 под XC8 компилятор. На сайте narodstream все хорошо разжёвано, от туда беру примеры, но нет примера именно с 74HC595. Спасибо.
расскажите что не получается? толи с пиком не разобрались, или с регистром? входные пины 595 [10] MR — сброс регистра, при подаче логического нуля на MR и единицы на STCP переводит все выходы в состояние логического нуля; [11] SH_CP — вход для тактовых импульсов; [12] ST_CP — линия прерываний; [13] OE — вход, переводящий выходы из высокоимпедансного состояния в рабочее; [14] DS — вход данных; [8] GND — Ground. Земля [16] VCC — Питание +5 В.
Если я вижу пример, то смогу что то сварганить для своих нужд, с ноля не напишу . Я не настолько знаю С. Это как читать книгу на английском, имея под рукой словарь.
МК: pic12f683; Программа: MPLAB X IDE; Компилятор: xc8 v2.10(2.05 тоже пробовал) Проблема: ножка порта сбрасывается на 0 через пару мкс после установления 1. Код: Спойлер// PIC12F683 Configuration Bit Settings
// 'C' source line config statements
// CONFIG #pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config MCLRE = OFF // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD) #pragma config CP = ON // Code Protection bit (Program memory code protection is enabled) #pragma config CPD = ON // Data Code Protection bit (Data memory code protection is enabled) #pragma config BOREN = OFF // Brown Out Detect (BOR disabled) #pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode is disabled) #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
// #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF
// MC CONFIG OSCCON=0b01110100; OSCTUNE=0b00001111;
GIE=1; // Global INTERRUPT on PEIE=1; INTE=1; // internal INTERRUPT on INTEDG=1; // Interrupt on rising edge T2CON=0; //Config TIMER2 PreScealer 1:1 PostScealer 1:1 PR2=90; // TMR2 interrupt, RX frequency TRISIO=0b00111100; // Set GP2 input GP1 GP0 output ANSEL=0; //Set ports as digital WPU=0b111000; //Disabble weak pull ups while(1) { if(i==255) { TMR2IE=0; i=0; CODE=0; RX=0; RXv=0; }
}
} сбрасывается ножка code (gp1) на ножке RX была подобная проблема когда запись была RX=!RX. с вводом переменной RXv все нормализовалось. я решил, что при чтении значения с порта, чтобы сделать инверсию он сбрасывался. но с ножкой CODE такой проблемы нет... она не читается в программе. Логика программы: по запросу с ТХ (прямоугольный импульс длиной около 50мс) по завершению идёт генерация импульсов синхронизации на RX а на ножке Code идёт пробитовая посылка на каждом пике RX перед спадом. Осцилограмма работы видно что логика работает 255 бит отправляются, но при передаче 0( т.е. 1 потому что через транзистор) на gp1 он появляется кратковременно и не остаётся в нем, а возвращается в 1( т.е в 0). оранжевым дорисовал как должно быть в начале идут 0 т.е. должна быть прямая. осцилограмма снята на выходе, т.е. после транзисторов. на прямую с мк то же самое только наоборот. Схема устройства:
в чем может быть причина такого поведения? компилятор чудит? осцилятор используется внутренний на 8Mhz, но кроме как что gp4,5 всегда на вход будут ничего не нашёл в этом режиме. или переферия какая сбрасывает на 0??
P.S. пока писал пришла в голову мысль, что может быть это из-за инверсии "!" ?? попробую завтра массив вручную инвертировать, хотя не очень логично т.к. RX=!RXv; проходит нормально...
Процедура RMW - чтение-модификация-запись. При записи в любой бит порта читается ВЕСЬ ПОРТ, затем модифицируется этот бит, затем результат записывается в ВЕСЬ ПОРТ. Чтение порта при записи бита В ЭТОМ СЕМЕЙСТВЕ МК происходит прямо с пинов, а не с выходной буферизованной защелки. Если пин сильно нагружен, то на нем может быть напряжение ниже порога единицы и при чтении на нем будет ноль. Таким образом, этот ноль будет перезаписан в этот пин при записи совершенно в другой пин этого порта. Тоже самое происходит, если записи следуют раньше, чем на пине устанавливается уровень, т.е. слишком быстро. Ворк эрраунд. Держать в коде копию порта и работать с ней, отдавая в порт только его копию целиком, а не побитно.
Процедура RMW - чтение-модификация-запись. При записи в любой бит порта читается ВЕСЬ ПОРТ, затем модифицируется этот бит, затем результат записывается в ВЕСЬ ПОРТ. Чтение порта при записи бита В ЭТОМ СЕМЕЙСТВЕ МК происходит прямо с пинов, а не с выходной буферизованной защелки. Если пин сильно нагружен, то на нем может быть напряжение ниже порога единицы и при чтении на нем будет ноль. Таким образом, этот ноль будет перезаписан в этот пин при записи совершенно в другой пин этого порта. Тоже самое происходит, если записи следуют раньше, чем на пине устанавливается уровень, т.е. слишком быстро. Ворк эрраунд. Держать в коде копию порта и работать с ней, отдавая в порт только его копию целиком, а не побитно.
уже справился, спасибо. вся проблема была в не отключённом компараторе, который на этом мк по умолчанию был включен. из-за этого было такое неадекватное поведение портов. за метод спасибо, я его как то встречал. и сейчас ещё напомнили. очень интересный способ вывода.
для паскаля вот разрабатывается транслятор, чтобы отлаживать на дельфях, а потом транслировать в код Си
как-то слишком просто... надо бы как-то так: на питоне транслятор, который транслирует код на асме в код на бейсике, на бейсике транслятор в паскаль для отладки в дельфи, а уж из дельфи транслятор в код Си... так лучше, имхо
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
ARV - я думаю, напрямую делать компилятор малоперспективно для маленьких опенсорсных проектов. Т.к. он всё равно будет хуже, чем MPlabX, и как только энтузиасты перестанут его поддерживать, то весь код превратиться в тыкву. А так можно дальше на Си проекты развивать.
Выводы всяких трансляторов из одного языка в дргуой обычно мало пригодные для правки человеком. С тем же успехом можно пытаться дизассемблер транслировать в C и пытаться править. Зачастую проще вручную переписать с одного языка на другой, чем пытаться разобраться в автотрансляции.
...обычно мало пригодные для правки человеком. С тем же успехом можно пытаться.....
Даладна!!! Коллеги, это только мне кажется, что ARV ерничает? Вообще то это был сарказм. И тут можно только поржать, но никак не обсуждать на полном серьезе перспективы.
А как в MPLAB X посмотреть дизасм? Компилятор XC8. Версии MPLAB X и компилятора последние. Вот только с Ассемблера перешел на СИ, написал работающую программу. Хотелось бы узнать мнение гуру о коде программы. Пойдет такое написание на СИ? Или что-то можно по другому скомпоновать в программе? Спойлер
Код:
while (1) { PWM1CON = 0b00000000; // отключаем ШИМ1 FVRCON = 0b00000000; // отключаем ИОН, отключаем температурный индикатор ADCON = 0b00000000; // отключаем модуль АЦП PORTA = 0; // все выходы порта переводим в низкое состояние __delay_ms(500); IOCIE = 1; // разрешаем прерывание по изменению уровня PORTA IOCAF = 0; // сбрасываем флаг IOCAF (свидетельствующий о прерывании RA3) SWDTEN = 0; // отключаем сторожевой таймер на период сна SLEEP(); // здоровый крепкий сон до пробуждения нажатием кнопки) IOCIE = 0; // запрет прерывания по изменению уровня PORTA SWDTEN = 1; // включаем сторожевой таймер
GO: for(n=0; n<=15000; n++) // время работы основного цикла программы, где 1000n соответствует ~ 1 минуте работы (максимальный n=65535, ТЕ 65мин) { if (!TK1) // если перемычка на 0, то бесконечный режим работы (без таймера)) { n=0; } CLRWDT(); __delay_ms(52); if (!TK) // если кнопка нажата - подаем короткий звуковой сигнал { PWM1EN = 1; // вкл ШИМ звукового сигнала нажатия кнопки __delay_ms(55); PWM1EN = 0; __delay_ms(999); if (!TK) // если кнопка нажата более 1 сек - отключаем питание { goto Power_OFF; } else // если кнопка нажата менее 1 сек - обнуляем таймер ожидания { goto GO; } }
GO_nDONE = 1; //начать преобразование АЦП while(GO_nDONE); //ожидание окончания преобразования АЦП if(ADRES > 86) //если U ниже 3.0В выключаем питание { goto Power_OFF; } else { if(ADRES > 80) //если U ниже 3.3В включим двойной предупредительный звуковой сигнал о низком заряде АКБ, который повторяется каждые 15с { if (i<2) { PWM1EN = 1; // вкл ШИМ для предупредительного звукового сигнала __delay_ms(55); PWM1EN = 0; // выкл ШИМ __delay_ms(33); } i++; } } if(n==14000) // вкл предупредительный 4-хкратный звуковой сигнал, предупреждающий о отключении питания, где 1000n соответствует ~ 1 минуте работы (максимальный n=65535, ТЕ 65мин) { for(m=0; m<=3; m++) { PWM1EN = 1; // вкл ШИМ для предупредительного звукового сигнала __delay_ms(155); PWM1EN = 0; // выкл ШИМ __delay_ms(77); } } }
Power_OFF: PWM1EN = 1; // вкл ШИМ для двухтонального сигнала выключения TMR2 = 0; // сброс TMR2 для исключения пауз между тонами PR2 = 6; // первый тон ~ 1,1 кГц PWM1DCH = 3; // -//- __delay_ms(111); TMR2 = 0; // сброс TMR2 для исключения пауз между тонами PR2 = 10; // второй тон ~ 700 Гц PWM1DCH = 5; // -//- __delay_ms(111); PWM1EN = 0; // выкл ШИМ LED = 0; // отключаем питание } return;
А как в MPLAB X посмотреть дизасм? Компилятор XC8. Версии MPLAB X и компилятора последние.
Включить отладку (можно через симулятор), потом Window->Debugging->Disassembly
Добавлено after 25 minutes 22 seconds: 4uvak, напишите модель МК для кода, так проверить удобнее будет собрав исходник.
Добавлено after 2 minutes 56 seconds: Вообще конечно видно, что переход был с асма ) Стилистика осталась в асм стиле. Вместо меток лучше в виде функций оформить. Да и вообще в Си метки почти никогда не нужны.
Добавлено after 23 minutes 7 seconds: Чисто в плане избавления от ненужных меток: Спойлер
Код:
void init() { PWM1CON = 0b00000000; // отключаем ШИМ1 FVRCON = 0b00000000; // отключаем ИОН, отключаем температурный индикатор ADCON = 0b00000000; // отключаем модуль АЦП PORTA = 0; // все выходы порта переводим в низкое состояние __delay_ms(500); IOCIE = 1; // разрешаем прерывание по изменению уровня PORTA IOCAF = 0; // сбрасываем флаг IOCAF (свидетельствующий о прерывании RA3) SWDTEN = 0; // отключаем сторожевой таймер на период сна SLEEP(); // здоровый крепкий сон до пробуждения нажатием кнопки) IOCIE = 0; // запрет прерывания по изменению уровня PORTA SWDTEN = 1; // включаем сторожевой таймер }
void power_off() { PWM1EN = 1; // вкл ШИМ для двухтонального сигнала выключения TMR2 = 0; // сброс TMR2 для исключения пауз между тонами PR2 = 6; // первый тон ~ 1,1 кГц PWM1DCH = 3; // -//- __delay_ms(111); TMR2 = 0; // сброс TMR2 для исключения пауз между тонами PR2 = 10; // второй тон ~ 700 Гц PWM1DCH = 5; // -//- __delay_ms(111); PWM1EN = 0; // выкл ШИМ LED = 0; // отключаем питание }
void main(void) { init(); power_on(); CLRWDT(); while (1) { for (n = 0; n <= 15000; n++) // время работы основного цикла программы, где 1000n соответствует ~ 1 минуте работы (максимальный n=65535, ТЕ 65мин) { if (!TK1) // если перемычка на 0, то бесконечный режим работы (без таймера)) { n = 0; } CLRWDT(); __delay_ms(52); if (!TK) // если кнопка нажата - подаем короткий звуковой сигнал { PWM1EN = 1; // вкл ШИМ звукового сигнала нажатия кнопки __delay_ms(55); PWM1EN = 0; __delay_ms(999); if (!TK) // если кнопка нажата более 1 сек - отключаем питание { power_off(); return; } else // если кнопка нажата менее 1 сек - обнуляем таймер ожидания { break; } }
GO_nDONE = 1; //начать преобразование АЦП while (GO_nDONE); //ожидание окончания преобразования АЦП if (ADRES > 86) //если U ниже 3.0В выключаем питание { power_off(); return; } else { if (ADRES > 80) //если U ниже 3.3В включим двойной предупредительный звуковой сигнал о низком заряде АКБ, который повторяется каждые 15с { if (i < 2) { PWM1EN = 1; // вкл ШИМ для предупредительного звукового сигнала __delay_ms(55); PWM1EN = 0; // выкл ШИМ __delay_ms(33); } i++; } } if (n == 14000) // вкл предупредительный 4-хкратный звуковой сигнал, предупреждающий о отключении питания, где 1000n соответствует ~ 1 минуте работы (максимальный n=65535, ТЕ 65мин) { for (m = 0; m <= 3; m++) { PWM1EN = 1; // вкл ШИМ для предупредительного звукового сигнала __delay_ms(155); PWM1EN = 0; // выкл ШИМ __delay_ms(77); } } } return; } }
Что еще я бы улучшил, но уже безотносительно перехода с асма: 1. Мне не нравится сброс n каждый раз в случае перемычки. Обычно перемычку на работающем ус-ве не меняют. Поэтому обычно значение перемычки считается только один раз. А дальше я бы просто сделал бы бесконечный цикл, где n приращивалось бы или нет. 2. Нажатие кнопки проверяется разово. При этом ожидание и замеры АЦП останавливаются. Дребезгом или дрочением кнопки можно тормознуть выполнение другого участка кода. 3. Вместо перехода на конец программы, где просто будет бесконечный цикл ничего не делания крутится, я бы в конце power_off() в спящий режим бы уходил бы постоянный.
Последний раз редактировалось NStorm Вт окт 20, 2020 13:47:05, всего редактировалось 1 раз.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 15
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения