Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Согласование переменных разных типов
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
GoodNews
Если есть одна переменная у которой тип "char", вторая переменная типа "uint16_t" на которой реализован счётчик. Как их представить в переменной типа "char" для последующей записи в порт LCD?

МК - mega16
Компилятор - AVR-GCC
volodya
Цитата(GoodNews @ Feb 4 2010, 00:22) *
Если есть одна переменная у которой тип "char", вторая переменная типа "uint16_t" на которой реализован счётчик. Как их представить в переменной типа "char" для последующей записи в порт LCD?


Стандартное преобразование типов С :

Код
{
   char chValH, chValL;
   uint16 uiCnt;

   chValL = (char) (uiCnt);
   chValH = (char) (uiCnt >> 8);
}


далее далее старшую и младшую часть в порт. Если счетчик обновляется в прерывании то предусмотреть запрет прерывания во время чтения счетчика.
Палыч
Цитата(GoodNews @ Feb 4 2010, 01:22) *
Как их представить в переменной типа "char" для последующей записи в порт LCD?
Вам - что, нужно получить последовательность символов, соответствующих значению счетчика? Тогда - функция sprintf. Ну, и поместить эту последовательность в переменную массив char'ов... Как-то так:
Код
uint16_t Cnt;
char Array[10];
sprintf(Array, "%d", Cnt);
GoodNews
Цитата(Палыч @ Feb 4 2010, 09:44) *
Вам - что, нужно получить последовательность символов, соответствующих значению счетчика? Тогда - функция sprintf. Ну, и поместить эту последовательность в переменную массив char'ов... Как-то так:
Код
uint16_t Cnt;
char Array[10];
sprintf(Array, "%d", Cnt);

Я хотел взять некоторое значение, например 125,3876, добавить к нему текст (в а конкретно "MHz"), и всё это отправить в lcd_putdata() в соответствующую строку дисплея (запись в дисплей у меня реализована, выбор строк тоже). Вот функция записи в дисплей:
Код
void lcd_putchar(char data)
{    
        LCD_CTL |= LCD_RS; //Включаем режим обработки данных дисплеем (если бит инвертирован, то - обработка инструкций)
    LCD_PORT = data;
        lcd_strobe();
        LCD_CTL &= ~(LCD_RS|LCD_RW);
}
void lcd_putdata(uint8_t line, char* data)
{
    lcd_select_addr(line);
    while(*data)
    {
        lcd_busy();
        lcd_putchar(*data++);
    }
}
int main(void)
{
///
    lcd_init();
    lcd_putdata(1, "1234567890ABCDEF");
    lcd_putdata(2, "GHIJKLMNOPQRSTUV");
    lcd_putdata(3, "WXYZ!@#$%^&*()_+");
///
.....
}
Палыч
Цитата(GoodNews @ Feb 4 2010, 11:54) *
Я хотел взять некоторое значение, например 125,3876, добавить к нему текст (в а конкретно "MHz"), и всё это отправить в lcd_putdata() в соответствующую строку дисплея (запись в дисплей у меня реализована, выбор строк тоже).
Ну, так и воспользуйтесь функцией sprintf - это самый простой, но, правда, и самый затратный по памяти способ. Правда, я не понял как Вы из целого значения желаете получить "125,3876"? Если в целой переменной у Вас храниться частота в килогерцах, то более 65535 поместить в неё не удастся...

PS. Для переменной типа uint_t нужно использовать sprintf(Array, "%u", Cnt);
GoodNews
Цитата(Палыч @ Feb 4 2010, 11:05) *
Ну, так и воспользуйтесь функцией sprintf - это самый простой, но, правда, и самый затратный по памяти способ. Правда, я не понял как Вы из целого значения желаете получить "125,3876"? Если в целой переменной у Вас храниться частота в килогерцах, то более 65535 поместить в неё не удастся...

PS. Для переменной типа uint_t нужно использовать sprintf(Array, "%u", Cnt);

Тут скорее надо float, я не подумал как-то. По памяти - я отрабатываю каждый модуль отдельно (LCD, kbd ...), а потом всё будет собрано для mega128.
Палыч
Цитата(GoodNews @ Feb 4 2010, 12:20) *
Тут скорее надо float...
Необязательно. Подключение функции sprintf с поддержкой float "отъест" очень большой кусок памяти. Обычно, выгоднее иметь переменную типа int (unsigned int) или long (unsigned long), а при форматировании разбить на "целую" и "дробную" части. Как-то так:
Код
char Str[11];
unsigned int Fr;// Частота кГц
unsigned int M, K; // МГц и кГц
M= Fr / 1000U;
K= Fr - M * 1000U; // или так K= Fr % 1000U;
sprintf(Str, "%2u,%03u МГц", M, K);
rezident
Цитата(GoodNews @ Feb 4 2010, 14:20) *
Тут скорее надо float, я не подумал как-то.
Да, да. Сначала во float преобразовать, а потом sprintf-ом на LCD вывести, и для этого mega на xmega поменять, потому что размера ОЗУ не хватает. sad.gif Вы бы погуглили вначале по теме BCD преобразования и использования fixed point арифметики. На форуме уже раз сто мусолили эти темы.
GoodNews
Цитата(rezident @ Feb 4 2010, 15:18) *
Да, да. Сначала во float преобразовать, а потом sprintf-ом на LCD вывести, и для этого mega на xmega поменять, потому что размера ОЗУ не хватает. sad.gif Вы бы погуглили вначале по теме BCD преобразования и использования fixed point арифметики. На форуме уже раз сто мусолили эти темы.

так планируется в дальнейшем использование mega128, просто mega16 доступнее в плане цены и если убью при прошивке (STK600 можно найти только на eBay), вот поэтому на mega16 испытываю модули по отдельности (lcd и пр.).
GoodNews
Решил попробовать использовать такой вариант кода (всё-таки float):
Код
char* get_freq(uint32_t Fr, uint8_t type)
{
    static char Str[16];
    static float tmp;
    tmp = Fr / 1000U;
    switch(type)
    {
        case (0): //KHz
            sprintf(Str, "%4.6fKHz", (double)tmp);
            return Str;
            break;
    /*    case (1): //MHz
            sprintf(Str, "%4.6fMHz", (double)tmp);
            return Str;
            break;
    */
    }
    return 0;
}
int main(void)
{
    uint32_t i = 560000;
    lcd_init();
/*...*/
    lcd_putdata(1, get_freq(i, 0));
/*...*/
}

Проблема в sprintf(Str, "%4.6fKHz", (double)tmp), так как в итоге ничего не отображается (просто пустая строка). Почему не хочет показывать, ведь вроде функцию вызвал правильно?
Палыч
Цитата(GoodNews @ Feb 5 2010, 15:09) *
Почему не хочет показывать, ведь вроде функцию вызвал правильно?
Функция printf (и еже с ними) ну очень прожорлива до памяти. Чтобы как-то это обойти, обычно, поставляется несколько вариантов библиотек, в которых от самых "худых" функций (поддерживают только сhar и int) до самых навороченных (это Ваш вариант - поддерживают плавучку). В зависимости от используемой среды разработки нужно как-то указать: какой вариант использовать...

Цитата(GoodNews @ Feb 5 2010, 15:09) *
Решил попробовать использовать такой вариант кода (всё-таки float):
Код
char* get_freq(uint32_t Fr, uint8_t type)
{
    static char Str[16];
    static float tmp;
    tmp = Fr / 1000U;
    /*...*/
}
Такое вычисление tmp - никуда не годится! Правильно записать tmp = Fr / 1000.0;

Цитата(GoodNews @ Feb 5 2010, 15:09) *
Код
sprintf(Str, "%4.6fKHz", (double)tmp);
Преобразование к double - абсолютно лишнее
GoodNews
Цитата(Палыч @ Feb 5 2010, 15:27) *
Функция printf (и еже с ними) ну очень прожорлива до памяти. Чтобы как-то это обойти, обычно, поставляется несколько вариантов библиотек, в которых от самых "худых" функций (поддерживают только сhar и int) до самых навороченных (это Ваш вариант - поддерживают плавучку). В зависимости от используемой среды разработки нужно как-то указать: какой вариант использовать...

Такое вычисление tmp - никуда не годится! Правильно записать tmp = Fr / 1000.0;

smile.gif среда разработки - Vim, набор библиотек - avr-libc, компилятор - avr-gcc, библиотека stdio.h из комплекта avr-libc.

Цитата(Палыч @ Feb 5 2010, 15:31) *
Преобразование к double - абсолютно лишнее

без него ругается, что tmp - float, а %4.6f - double!
GoodNews
Цитата(ukpyr @ Feb 5 2010, 19:17) *

спасибо, попытаюсь разобраться. но всё равно не понятно, почему в моём случае не работает именно так, как я написал (и как заставить работать в таком виде...)?
ukpyr
Цитата
Проблема в sprintf(Str, "%4.6fKHz", (double)tmp), так как в итоге ничего не отображается (просто пустая строка). Почему не хочет показывать, ведь вроде функцию вызвал правильно?
а что вы передаете в lcd_putdata (что возвращает get_freq) ?
GoodNews
Цитата(ukpyr @ Feb 5 2010, 21:06) *
а что вы передаете в lcd_putdata (что возвращает get_freq) ?

в lcd_putdata уходит char (который возвращает get_freq), так как если передавать в чистом виде числовое значение, то дисплей его считает как код символа и соответственно показывает символ, соответствующий полученному значению.
GoodNews
На данный момент решён вопрос с отображение значений во float.
Действия следующие:
Код
char* get_freq()
{
    static char Str[16];
    double tmp;
    tmp = 560.1223;
    sprintf(Str, "%4.4fkHz", tmp);
    return Str;

}

Т.е. в таком виде работает отлично (плюс дополнительные команды к линкеру для подключения внешних библиотек) + 2к к размеру флэша.
GoodNews
Вариант #2. В таком виде - работает. Если раскомментить и вызвать через функцию - виснет. Почему? Проц поставил ATmega32.
main.h
Код
#ifndef _MAIN_H
#define _MAIN_H
#endif
#define khzFmt "F=%4.4fkHz"
#define mhzFmt "F=%3.4fMHz"
char buf[16];

main.c
Код
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
#include <stdio.h>
#include <stdint.h>
#include "lcd.h"
#include "main.h"
/*void hzToStr(char* buf, const uint32_t hz, uint8_t freqSelect)
{
        double fd = (float)hz / 1000.0f;
    if (freqSelect == 0)
        snprintf(buf, sizeof(buf), khzFmt, fd);
    if (freqSelect == 1)
        snprintf(buf, sizeof(buf), mhzFmt, fd);
}*/
int main(void)
{
        uint32_t hz = 1325235;
        lcd_init();
        double fd = (double)hz / 1000.0f;
    snprintf(buf, sizeof(buf), khzFmt, fd);
        lcd_putdata(1, (char*)buf);
    //hzToStr(buf, hz, 0);
    //lcd_putdata(1, (char*)buf);
    lcd_putdata(2, "adflasdf");
        while(1){;}
}
ReAl
Если уж использовать в WinAVR printf, то тогда так:

Код
void lcd_putchar(char data); // то, что уже есть

int lcd_file_putc(char ch, FILE * stream)
{
    (void) stream;
    lcd_putchar(ch);
    return 0;
}

// аналогично создаём и для UART
void  uart_putchar(char ch); // он может вообще в кольцевой буфер помещать, ждать только если места нет
int uart_file_putc(char ch, FILE * stream)
{
    (void) stream;
    if(ch == '\n')
        uart_putchar('\r');
    uart_putchar(ch);
    return 0;
}


FILE lcd_file = FDEV_SETUP_STREAM(lcd_file_putc, 0, _FDEV_SETUP_WRITE);
FILE uart_file = FDEV_SETUP_STREAM(uart_file_putc, uart_file_getc, _FDEV_SETUP_WRITE);

#define lcd_stream (&lcd_file);
#define uart_stream (&uart_file);

    fprintf_P( lcd_stream, PSTR("Freq %6.3fMHz"), freq);

    fputs_P( PSTR("Hello!\n"), uart_stream);
    fprintf_P( uart_stream, PSTR("Freq %6.3fMHz"), freq);

А для ЖКИ можно и вообще так:
Код
void lcd_printf_P(uint8_t x, uint8_t y, prog_char *fmt, ...) __attribute__((format(printf, 3, 4)));

void lcd_printf_P(uint8_t x, uint8_t y, prog_char *fmt, ...)
{
    lcd_gotoxy(x,y);

    va_list vl;
    va_start(vl, fmt);
    vfprintf_P( lcd_stream, fmt, vl);
    va_end(vl);
}

    lcd_printf_P(1, 5, PSTR("%6.3MHz"), freq);

Раз уж платить увеличенным расходом кода, то хоть знать за что.

Цитата(GoodNews @ Feb 7 2010, 14:30) *
Если раскомментить и вызвать через функцию - виснет. Почему?
Да так вроде всё нормально. Не вижу причины :-(

Определять переменные в .h нехорошо (это я про char buf[16]), но к зависанию это не имеет отношения.
GoodNews
Цитата(ReAl @ Feb 7 2010, 15:16) *
Если уж использовать в WinAVR printf

Собственно я не WinAVR использую. Платформа Linux, ядро 2.6.28-17_x86-64, компилятор AVR-GCC, прогер - avrdude, программатор - AVRISP (JONIS+ в запасе), набор библиотек avr-libc.
ReAl
Цитата(GoodNews @ Feb 7 2010, 17:49) *
Собственно я не WinAVR использую. Платформа Linux, ядро 2.6.28-17_x86-64, компилятор AVR-GCC, прогер - avrdude, программатор - AVRISP (JONIS+ в запасе), набор библиотек avr-libc.
Да это я по привычке, конечно, имелись ввиду avr-gcc и avr-libc, а инсталлятором этого добра и средой для выполнения служат WinAVR+Windows или apt + Linux - какая разница? У меня проекты собираются и там, и там.
GoodNews
Цитата(ReAl @ Feb 7 2010, 19:05) *
Да это я по привычке, конечно, имелись ввиду avr-gcc и avr-libc, а инсталлятором этого добра и средой для выполнения служат WinAVR+Windows или apt + Linux - какая разница? У меня проекты собираются и там, и там.

Ну там сильно отличий наверное нету. Только библиотеки по-разному называются (ioavr.h против io.h насколько я помню). Но не принципиально. Я думаю что реализую через int, так как всё-таки работает не так, как хотелось бы. Пока попробую через int в общем. Спасибо!
XVR
Пока видна 1 ошибка - sizeof(buf) в hzToStr и main не равны, т.к. в main это массив, а в hzToStr это указатель (параметр)
GoodNews
Цитата(XVR @ Feb 8 2010, 13:01) *
Пока видна 1 ошибка - sizeof(buf) в hzToStr и main не равны, т.к. в main это массив, а в hzToStr это указатель (параметр)

Его надо было тоже как указатель использовать в main?
ReAl
Цитата(GoodNews @ Feb 7 2010, 19:51) *
Ну там сильно отличий наверное нету. Только библиотеки по-разному называются (ioavr.h против io.h насколько я помню).
Вообще нету.
#include <avr/io.h> и побежали.
Я же говорю - компилирутся и под вин, и под убунтой одни и те же проекты без изменений вообще и без ОС-зависимых define-ов.


Цитата(GoodNews @ Feb 8 2010, 18:37) *
Его надо было тоже как указатель использовать в main?

Нет, в hzToStr нужно отдельным параметром передавать длину буфера.
В первый просмотр я, наверное, ослеп, раз такое не заметил :-(
GoodNews
2ReAl:
понятно. т.е. размерность массива buf вычислить в функции, из которой будет вызываться hzToStr, а потом уже передавать в качестве параметра в hzToStr.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.