Добавлено after 4 hours 25 minutes 39 seconds: serg_svd, Дело было в SSPSTAT. Подпилил ваш драйвер ssd1306 под свой i2c, закинул в отладочную плату, красота.
Добавлено after 5 minutes 32 seconds:
хотя у меня подтяжка на плате через резисторы 10к к +5 В и все норм работает и раньше работало)
[uquote="XoXoJI",url="/forum/viewtopic.php?p=3686071#p3686071"]хотя у меня подтяжка на плате через резисторы 10к к +5 В и все норм работает и раньше работало)[/uquote]
Спасибо за помощь!
У меня тоже резисторы 10кОм были, но я поверх них запаял еще по 10к. В итоге стало 5к подтягивающие. Просто думал в них дело...
Схему на плату ssd1306 я только огрызок нашел, но в ней тоже подтягивающие по питанию после стабилизатора подключены. На своей плате я тщательно все прозвонил. Не думаю, что китайцы столько модификаций плат лепят.
"Чтобы правильно задать вопрос, нужно знать бо́льшую часть ответа." Ро́берт Ше́кли
Я правильных ответов знаю мало, поэтому не стесняюсь и много спрашиваю.
Кстати попробуйте увеличить частоту i2c. Для 128х64 на частоте 100кгц медленный вывод шрифтом 5х8. Чтоб заполнить весь экран символами уходит гдето 0.5 секунды.
[uquote="XoXoJI",url="/forum/viewtopic.php?p=3686562#p3686562"]Кстати попробуйте увеличить частоту i2c.[/uquote]
Игрался с частотой. Насколько знаю, предел 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 - чтение-модификация-запись.
При записи в любой бит порта читается ВЕСЬ ПОРТ, затем модифицируется этот бит, затем результат записывается в ВЕСЬ ПОРТ. Чтение порта при записи бита В ЭТОМ СЕМЕЙСТВЕ МК происходит прямо с пинов, а не с выходной буферизованной защелки. Если пин сильно нагружен, то на нем может быть напряжение ниже порога единицы и при чтении на нем будет ноль. Таким образом, этот ноль будет перезаписан в этот пин при записи совершенно в другой пин этого порта. Тоже самое происходит, если записи следуют раньше, чем на пине устанавливается уровень, т.е. слишком быстро.
Ворк эрраунд. Держать в коде копию порта и работать с ней, отдавая в порт только его копию целиком, а не побитно.
[uquote="КРАМ",url="/forum/viewtopic.php?p=3779600#p3779600"]Процедура RMW - чтение-модификация-запись.
При записи в любой бит порта читается ВЕСЬ ПОРТ, затем модифицируется этот бит, затем результат записывается в ВЕСЬ ПОРТ. Чтение порта при записи бита В ЭТОМ СЕМЕЙСТВЕ МК происходит прямо с пинов, а не с выходной буферизованной защелки. Если пин сильно нагружен, то на нем может быть напряжение ниже порога единицы и при чтении на нем будет ноль. Таким образом, этот ноль будет перезаписан в этот пин при записи совершенно в другой пин этого порта. Тоже самое происходит, если записи следуют раньше, чем на пине устанавливается уровень, т.е. слишком быстро.
Ворк эрраунд. Держать в коде копию порта и работать с ней, отдавая в порт только его копию целиком, а не побитно.[/uquote]
уже справился, спасибо. вся проблема была в не отключённом компараторе, который на этом мк по умолчанию был включен. из-за этого было такое неадекватное поведение портов.
за метод спасибо, я его как то встречал. и сейчас ещё напомнили. очень интересный способ вывода.
[uquote="Ariadna-on-Line",url="/forum/viewtopic.php?p=3753401#p3753401"]На Си писАть не люблю. Там думать надо над языком. Вот на Бейсике - там думать надо именно над "задуманным".[/uquote] -не знаю, как на бейсике, а для паскаля вот разрабатывается транслятор, чтобы отлаживать на дельфях, а потом транслировать в код Си.
lin17 писал(а):для паскаля вот разрабатывается транслятор, чтобы отлаживать на дельфях, а потом транслировать в код Си
как-то слишком просто... надо бы как-то так: на питоне транслятор, который транслирует код на асме в код на бейсике, на бейсике транслятор в паскаль для отладки в дельфи, а уж из дельфи транслятор в код Си... так лучше, имхо
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
ARV - я думаю, напрямую делать компилятор малоперспективно для маленьких опенсорсных проектов. Т.к. он всё равно будет хуже, чем MPlabX, и как только энтузиасты перестанут его поддерживать, то весь код превратиться в тыкву. А так можно дальше на Си проекты развивать.
Выводы всяких трансляторов из одного языка в дргуой обычно мало пригодные для правки человеком. С тем же успехом можно пытаться дизассемблер транслировать в C и пытаться править. Зачастую проще вручную переписать с одного языка на другой, чем пытаться разобраться в автотрансляции.
[uquote="lin17",url="/forum/viewtopic.php?p=3867637#p3867637"]ARV - я думаю...[/uquote]
NStorm писал(а):...обычно мало пригодные для правки человеком. С тем же успехом можно пытаться.....
Даладна!!!
Коллеги, это только мне кажется, что ARV ерничает? Вообще то это был сарказм. И тут можно только поржать, но никак не обсуждать на полном серьезе перспективы.
А как в MPLAB X посмотреть дизасм? Компилятор XC8. Версии MPLAB X и компилятора последние.
Вот только с Ассемблера перешел на СИ, написал работающую программу. Хотелось бы узнать мнение гуру о коде программы. Пойдет такое написание на СИ? Или что-то можно по другому скомпоновать в программе?
Спойлер
[uquote="4uvak",url="/forum/viewtopic.php?p=3909568#p3909568"]А как в MPLAB X посмотреть дизасм? Компилятор XC8. Версии MPLAB X и компилятора последние.[/uquote]
Включить отладку (можно через симулятор), потом 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_on() {
LED = 1; // включаем питание
PWM1CON = 0b11000000; // вкл ШИМ для двухтонального сигнала включения
TMR2 = 0; // сброс TMR2 для исключения пауз между тонами
PR2 = 10; // первый тон сигнала включения ~ 700 Гц
PWM1DCH = 5; // -//-
__delay_ms(111);
TMR2 = 0; // сброс TMR2 для исключения пауз между тонами
PR2 = 6; // второй тон сигнала включения ~ 1,1 кГц
PWM1DCH = 3; // -//-
__delay_ms(111);
PWM1CON = 0b01000000; // выкл ШИМ
FVRCON = 0b10000001; // включаем ИОН 1,024V, отключаем температурный индикатор
ADCON = 0b00011101; // включаем модуль АЦП, FVR вход (фиксированное опорное напряжение), FOSC/2
}
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 раз.