WinAvr в вопросах и ответах

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
vitalik_1984
Поставщик валерьянки для Кота
Сообщения: 2482
Зарегистрирован: Пт авг 27, 2010 05:57:06
Откуда: Тюмень
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение vitalik_1984 »

Бесполезная трата временных ресурсов на подсчет символов, а потом еще и на вывод.Тем более если в буфере у вас находится не ноль, судя по картинке.
Лучше уж тогда использовать

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


Lcd_send_buffer
(unsigned char * buffs){
    while (*buffs[i]){
    Lcd_send_char(*buffs[i++]);
    }
}
 

и буфер заполнять так

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

 
sprintf
(buffer"Out= %d/0"1234); 
 


Вроде так как то.Поправьте, если что не так.Пока нечем проверить
Аватара пользователя
U235
Встал на лапы
Сообщения: 135
Зарегистрирован: Вт фев 21, 2012 20:42:26
Откуда: Санкт-Петербург, Россия, Земля

Re: WinAvr в вопросах и ответах

Сообщение U235 »

vitalik_1984 писал(а):Вроде так как то.Поправьте, если что не так.

А чего тут поправлять - это оптимальный вариант.
Только /0 лишнее - sprintf и так вставляет завершающий ноль.
А из наших труб идет необычный дым. Стой! Опасная зона! Работа мозга!...
Аватара пользователя
vitalik_1984
Поставщик валерьянки для Кота
Сообщения: 2482
Зарегистрирован: Пт авг 27, 2010 05:57:06
Откуда: Тюмень
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение vitalik_1984 »

Вставлять то вставляет, только почему на экране появляются палочки?Получается это такой пользовательский символ выводится.
И если это он, то получается, что такой функцией уже нельзя будет вывести пользовательский символ с адресом 0.Так выходит?
Аватара пользователя
U235
Встал на лапы
Сообщения: 135
Зарегистрирован: Вт фев 21, 2012 20:42:26
Откуда: Санкт-Петербург, Россия, Земля

Re: WinAvr в вопросах и ответах

Сообщение U235 »

Мне видится это так.
Изначально буфер заполнен нулями. Потом функция sprintf кладёт туда строку и 0x00. Функция

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

LCDString(buffer, 16);
посылает весь буфер, включая нули, в индикатор. А индикатор печатает 0x00 как палочки.
А из наших труб идет необычный дым. Стой! Опасная зона! Работа мозга!...
Аватара пользователя
rs39
Открыл глаза
Сообщения: 53
Зарегистрирован: Сб май 07, 2011 14:35:24
Откуда: Россия

Re: WinAvr в вопросах и ответах

Сообщение rs39 »

Еще вначале эксперимента инициализировал буфер заправляя нулями специально, перед тем как использовать. Все 16 ячеек. Палочки так и оставались. И скорее всего
А индикатор печатает 0x00 как палочки.
так и выходит.
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение avreal »

vitalik_1984 писал(а):И если это он, то получается, что такой функцией уже нельзя будет вывести пользовательский символ с адресом 0.Так выходит?
Можно. Как адрес 8.
У HD44780 пользовательсике символы в адресах 0..7 продублированы в 8..15, т.е. любой символ по адресу A Є {0..7} можно выводить по адресу A+8 и наоборот. Я только адресами 8..15 всегда и пользовался.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение avreal »

vitalik_1984 писал(а):Лучше уж тогда использовать

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

Lcd_send_buffer(unsigned char * buffs){
    while (*buffs[i]){
        Lcd_send_char(*buffs[i++]);
    }
}
 
Оставить что-то одно. Или индексацию

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

Lcd_send_buffer(unsigned char * buffs){
    unsigned char i = 0;
    while (buffs[i]) Lcd_send_char(buffs[i++]);
}
 
или разименование

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

Lcd_send_buffer(unsigned char * buffs){
    while (*buffs) Lcd_send_char(*buffs++);
}
 
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
vitalik_1984
Поставщик валерьянки для Кота
Сообщения: 2482
Зарегистрирован: Пт авг 27, 2010 05:57:06
Откуда: Тюмень
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение vitalik_1984 »

Во, во точно так и нужно.Забыл как правильно.Хотя второй вариант мне кажется проще и по написанию и лишние переменные не нужно объявлять.Компилятор сам где нужно создаст.
Аватара пользователя
Goldsmith
Опытный кот
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение Goldsmith »

rs39 писал(а):Еще вначале эксперимента инициализировал буфер заправляя нулями специально, перед тем как использовать. Все 16 ячеек. Палочки так и оставались.
Может, имеет смысл прописать его пробелами вместо нулей?
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Аватара пользователя
rs39
Открыл глаза
Сообщения: 53
Зарегистрирован: Сб май 07, 2011 14:35:24
Откуда: Россия

Re: WinAvr в вопросах и ответах

Сообщение rs39 »

Можно конечно, но с условием что буфер в программе будет использоваться всего один раз.
А иначе перед функцией sprintf это нужно будет делать каждый раз. Для этого удобнее всего написать отдельную функцию, в ней с помощью цикла заполнять буфер пробелами. Но стоит ли оно того.. Вроде как получается лишняя трата времени на заполнение неиспользуемых оставшихся ячеек, если строка в данный момент значительно короче.
Последний раз редактировалось rs39 Сб сен 22, 2012 20:51:28, всего редактировалось 2 раза.
Аватара пользователя
vitalik_1984
Поставщик валерьянки для Кота
Сообщения: 2482
Зарегистрирован: Пт авг 27, 2010 05:57:06
Откуда: Тюмень
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение vitalik_1984 »

Может, имеет смысл прописать его пробелами вместо нулей?

Да с нулями нормально, только не выводить что попало, если только не нужно затирать предыдущее изображение.

Я еще не добрался до своего дисплея, но собираюсь именно затирать вместо очистки дисплея.
То есть хранить полный массив дисплея в буфере Мк.Пока вот не знаю чем это грозит.
Аватара пользователя
rs39
Открыл глаза
Сообщения: 53
Зарегистрирован: Сб май 07, 2011 14:35:24
Откуда: Россия

Re: WinAvr в вопросах и ответах

Сообщение rs39 »

vitalik_1984 писал(а):

Я еще не добрался до своего дисплея, но собираюсь именно затирать вместо очистки дисплея.

Уточните пожалуйста, в каком смысле "затирать"? Просто писать данные в LCD поверх, либо все-же подавать на него какие то команды перед записью? У меня сейчас отладочная под рукой, могу попробовать.
Аватара пользователя
vitalik_1984
Поставщик валерьянки для Кота
Сообщения: 2482
Зарегистрирован: Пт авг 27, 2010 05:57:06
Откуда: Тюмень
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение vitalik_1984 »

Ну то есть на первую позицию и поехали выводить всю длину строки.
И так с каждой строкой.
Аватара пользователя
rs39
Открыл глаза
Сообщения: 53
Зарегистрирован: Сб май 07, 2011 14:35:24
Откуда: Россия

Re: WinAvr в вопросах и ответах

Сообщение rs39 »

Ок ясно.
Сейчас попробовал сделать. Из минусов пока ничего не заметил. А вот плюсы визуально есть. Не стало мерцания LCD, которое вероятнее всего происходило в момент LCD_Clear.
Массив конечно приходится "чистить" (заполнять нулями, пробелами) всегда перред sprintf.
Аватара пользователя
vitalik_1984
Поставщик валерьянки для Кота
Сообщения: 2482
Зарегистрирован: Пт авг 27, 2010 05:57:06
Откуда: Тюмень
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение vitalik_1984 »

Я где то читал, что с помощью этой функции делать строку определенной длины с заполнением любыми символами.Только вот уже не помню как точно это все выглядит и где посмотреть можно.
Кстати не нужно даже делать лишних движений сама функция sprintf в некоторых интерпретациях считает сколько в ней символов.И оставшееся можно дополнять пробелами.
Аватара пользователя
rs39
Открыл глаза
Сообщения: 53
Зарегистрирован: Сб май 07, 2011 14:35:24
Откуда: Россия

Re: WinAvr в вопросах и ответах

Сообщение rs39 »

Наткнулся на грабли. Сначала не придал значения, думал может в функции очистки буфера ошибся когда писал:

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

//Функция очистки буфера
void clear_buff(unsigned char *buff)
{
unsigned char i=0;
while(i<16)
   {
    buff[i]=' ';
   i++;
   }
}

но оказалось все правильно.
Дело в том что sprintf в конце строки как правило ставит \0 - так вот этот ноль зараза все-равно отображается в конце строки на LCD, и догадайтесь с первого раза ввиде чего? Да, именно в виде 2-х вертикальных палочек :))

Изображение

Да, забыл добавить комментарий к картинке.
Нижнюю строку "Влажность" не берем в расче, т.к. это просто статичная переменная в прогмем, для наглядности.
А вот верхняя с температурой - она и есть, формируемая sprintf
Вложения
lcd2.jpg
(14.83 КБ) 963 скачивания
Последний раз редактировалось rs39 Сб сен 22, 2012 23:24:18, всего редактировалось 1 раз.
Аватара пользователя
vitalik_1984
Поставщик валерьянки для Кота
Сообщения: 2482
Зарегистрирован: Пт авг 27, 2010 05:57:06
Откуда: Тюмень
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение vitalik_1984 »

Уж проще запихать в эту ячейку пустой символ.Может более опытные мастера подскажут что как можно сделать?

Могу предложить вот что :сделать функцию вывода буфера через вывод единичного символа и достигнув нулевого символа заполнять дальше пробелами.
Пока что с телефона подсиживаю так что кроме догадок ничего не могу предложить.
Аватара пользователя
U235
Встал на лапы
Сообщения: 135
Зарегистрирован: Вт фев 21, 2012 20:42:26
Откуда: Санкт-Петербург, Россия, Земля

Re: WinAvr в вопросах и ответах

Сообщение U235 »

На мой взгляд, проще всего не выводить каждый раз весь буфер, а делать печать только того, что действительно изменилось. При выводе чисел проблема неполного стирания предыдущего значения решается легко - нужно указать функции sprintf минимальную ширину числа. Тогда, если число занимает меньше символов, функция добавляет пробелов.
В одном заброшенном проекте я делал функцию, которая выводила информацию на экран от мобильника. В одном из параметров функции передавались битовые флаги, указывающие какой именно участок надо перерисовать. Это экономило кучу времени, да и мелькания не было.
А из наших труб идет необычный дым. Стой! Опасная зона! Работа мозга!...
Аватара пользователя
rs39
Открыл глаза
Сообщения: 53
Зарегистрирован: Сб май 07, 2011 14:35:24
Откуда: Россия

Re: WinAvr в вопросах и ответах

Сообщение rs39 »

U235 писал(а):При выводе чисел проблема неполного стирания предыдущего значения решается легко - нужно указать функции sprintf минимальную ширину числа. Тогда, если число занимает меньше символов, функция добавляет пробелов.

Да, пожалуй самый оптимальный вариант.
Следуя ему поступил следующим образом:
Зная сколько символов будет занято строкой, с учетом ширины числа (от 0 до 999 к примеру) задал в sprintf %3d, получилось 3, без учета символа завершения строки.
Все ранее навешанные функции strlen, заполнения буфера - убрал. Буфер так-же инициализировал в 3 ячейки супротив 16.
Функция очистки LCD тоже не нужна, т.к. длинна строки определена заранее(%3d).
Итог - код без лишних наворотов, мерцания дисплея нет, результат отображения без мусора.

Рабочий образец кода:

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

        unsigned char buffer[3];
        ...
        val = 999;
        sprintf(buffer,"%3d",val); // Заполняем буфер результатом, символ окончания строки невсчет
        LCDGotoXY(0, 0);
        LCDstring(buffer,3);
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: WinAvr в вопросах и ответах

Сообщение avreal »

rs39 писал(а):Рабочий образец кода:
Плохо.

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

        unsigned char buffer[3];   // <---- Буфер на три символа
        ...
        sprintf(buffer,"%3d",val);  // <---- пишется три симола и завершающий 0 за ними, итого 4 !
Будет переполнение буфера, а там уж как [не]повезёт.

Я делаю без промежуточных буферов. avr-gcc (WinAVR) позволяет так:

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

#include <stdio.h>
#include <avr/pgmspace.h> // Размещать форматные строки в ОЗУ жаба давит

#include "lcd.h"  // отсюда lcd_putchar да lcd_goxy

// Переходник от "файлового" putc к LCD-шному putchar
int lcd_file_putc(char ch, FILE * stream)
{
    (void) stream;
    lcd_putchar(ch);
    return 0;
}

// Инициализация файлового объекта LCD
FILE lcd_file = FDEV_SETUP_STREAM(lcd_file_putc, 0, _FDEV_SETUP_WRITE);

// Для удобства
#define flcd (&lcd_file)     
Где-то в lcd.h определены строки с кодами символов в пользовательском знакогенераторе, как-то так:

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

// Символ градусов цельсия ° занесён в знакогенератор по адресу 0, он же 8
#define LCD_CELSIUS_STR "\x08"     
Теперь можно так -- никаких промежуточных строк и завершающих нулей, пойдёт посимвольно прямо на индикатор.

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

    lcd_goxy(1,3);
    fprintf_P( flcd, PSTR("t=%3d" LCD_CELSIUS_STR "C"), temperature); 
Или вообще к первому фрагменту кода добавляем

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

#include <stdrag.h> 

void lcd_printf_P(uint8_t x, uint8_t y, const prog_char * fmt, ...)
{
    lcd_goxy(x,y);
    va_list va;
    va_start(va, fmt);
    vfprintf_P(flcd, fmt, va);
    va_end(va);
}
 
И пишем одной строкой переход к координатам и вывод:

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

    lcd_printf_P(1, 3, PSTR("t=%3d" LCD_CELSIUS_STR "C"), temperature); 

Примечание:
В языке C запись "t=%3d" LCD_CELSIUS_STR "C" даёт склеивание фрагментов строк в одну строку "t=%3d\x08C", но не нужно помнить, какой символ на каком номере и не будет проблем, если после \x08 идут опять цифры, в виде подстрок они точно не приклеятся к \x08

По поводу размера кода можно не беспокоиться, так как в библиотеке avr-libc функция sprintf сама сделана через порождение файлового объекта с флагами вывода в массив символов и с полнім набором va_start/vfprintf/va_end:

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

int sprintf(char *s, const char *fmt, ...)
{
    va_list ap;
    FILE f;
    int i;

    f.flags = __SWR | __SSTR;
    f.buf = s;
    f.size = INT_MAX;
    va_start(ap, fmt);
    i = vfprintf(&f, fmt, ap);
    va_end(ap);
    s[f.len] = 0;

    return i;
}
 
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Ответить

Вернуться в «AVR»