Владислав Бобриков

Перевод строки в число и наоборот

41 сообщение в этой теме

Ребята, всем привет !
Вот стоит задача, с матричной клавиатуры считать 5 циферок, и кинуть их в инт, а после этого снова в строку(массив чар) (пишу на си).

Суть в том, что пользователь вводит данные с клавиатуры для одной настройки,  когда он вводит каждое число присваивается каждому элементу массива. Когда массив заполнен числами, то нужно его конвертировать в число инт, или любое целочисленное, так как потом нужно это число записать в еепром память. использовал функции atoi и itoa( вместо этой еще sprintf), а после конвертации в инт, для теста, решил числа из инта снова в массив чар(строку) конвертить, и вывести. Вывожу конечно же на лсд1602. Работаю в CodeVisionAVR на атмеге16.
И все бы ничего, но когда ты вводишь допустим 95430, то по логике, должно же 2 раза конвертнуться, и вывести на лсд тоже самое, но не тут то было,  выводит просто рандомное чилсо например -9213 и тд.

Не знаю как с этим бороться, обшарил уже весь инет, тут, как в ванильном си шарпе нет методов IntToStr и тд.

Еще хочу узнать как правильно работать с епром памятью. Ну то есть вот у меня будет функция на ввод клавиатуры, когда юзер впервые подключит устройство(кстати это курсач такой), он должен будет ввести настройки, после этого, при включении питания девайса, функция опроса клавиатуры и создание этих настроек не должна вызываться. Подумал, и понял что просто сделать флаг на епром, то есть сначала флаг=0, когда равен 0 заходит в первую настройку, когда 1 - во вторую, когда вторая настройка прошла флаг = 2, и по логике с нового включения устройства программа должна не заходить в функцию опроса, как это сделать не очень понимаю.

 

вот говнокод:



#include <mega16.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <delay.h>
#include <alcd.h>
#include <keyboard.h>
#include <math.h>



__eeprom int FZ, MR;
int flag;

char buf=0;
char FZ_[5];
char MR_[4];
char buuf[4]={'1','2','3','4'};
char kek[4];
int i;
int temp_FZ;

 /*int StrToInt(const char* snum)
{
    int idx, strIdx = 0, accum = 0, numIsNeg = 0;
    const unsigned int NUMLEN = (int)strlen(snum);

    /* Check if negative number and flag it. */
    if(snum[0] == 0x2d)
        numIsNeg = 1;

    for(idx = NUMLEN - 1; idx >= 0; idx--)
    {
        /* Only process numbers from 0 through 9. */
        if(snum[strIdx] >= 0x30 && snum[strIdx] <= 0x39)
            accum += (snum[strIdx] - 0x30) * pow(10, idx);

        strIdx++;
    }

    /* Check flag to see if originally passed -ve number and convert result if so. */
    if(!numIsNeg)
        return accum;
    else
        return accum * -1;
}
      */



 void main(void)
{
DDRA=(0<<DDA7) | (0<<DDA6) | (0<<DDA5) | (0<<DDA4) | (0<<DDA3) | (0<<DDA2) | (0<<DDA1) | (0<<DDA0);
PORTA=(0<<PORTA7) | (0<<PORTA6) | (0<<PORTA5) | (0<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);
DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);
DDRC=(0<<DDC7) | (0<<DDC6) | (0<<DDC5) | (0<<DDC4) | (0<<DDC3) | (0<<DDC2) | (0<<DDC1) | (0<<DDC0);
PORTC=(0<<PORTC7) | (0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);
DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);
TCCR0=(0<<WGM00) | (0<<COM01) | (0<<COM00) | (0<<WGM01) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0=0x00;
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
ASSR=0<<AS2;
TCCR2=(0<<PWM2) | (0<<COM21) | (0<<COM20) | (0<<CTC2) | (0<<CS22) | (0<<CS21) | (0<<CS20);
TCNT2=0x00;
OCR2=0x00;
TIMSK=(0<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<TOIE1) | (0<<OCIE0) | (0<<TOIE0);
MCUCR=(0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);
MCUCSR=(0<<ISC2);
UCSRB=(0<<RXCIE) | (0<<TXCIE) | (0<<UDRIE) | (0<<RXEN) | (0<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
SFIOR=(0<<ACME);
ADCSRA=(0<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);
SPCR=(0<<SPIE) | (0<<SPE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);
TWCR=(0<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWEN) | (0<<TWIE);

flag = 0;
lcd_init(16);
KEYB_Init();
     
while (1)
      {
             if(flag == 0)
            {
                for( i = 0; i<5; i++)
                {   check_again:
                KEYB_ScanKeyboard();
                buf = KEYB_GetKey();
                if(buf == NULL) goto check_again;
                FZ_[i] = buf;
                lcd_gotoxy(0,1);
                lcd_putsf("FZ");
                lcd_gotoxy(i,0);
                lcd_putchar(FZ_[i]);
                }      
                flag=1;
                  
                 temp_FZ = atoi(FZ_);
                 sprintf(kek,"%d", temp_FZ);
                 
                 delay_ms(5000);
                 lcd_clear();
            }        
               
               
                
        lcd_gotoxy(0,0);
        lcd_puts(kek);
        
        /*for(i = 0; i<temp_FZ;i++)
        {
            temp_FZ = temp_FZ - i;
            itoa(temp_FZ, FZ_);
            delay_ms(1000);
            lcd_gotoxy(0,0);
            lcd_puts(FZ_);                             
            
        }
       // lcd_gotoxy(0,0);
        //lcd_puts(FZ_);
                        */
 }   
}

photo_2018-12-16_20-51-43.thumb.jpg.b30e04d20212191b6ce1e98dd81f80ee.jpg

Это то что ввел пользователь, ну ввел конечно же я))
а это, то что выдали эти функции преобразования.

photo_2018-12-16_20-51-45.thumb.jpg.e3c0a30258edc9c0b2a71db5a0322bb7.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    568

У Вас переполнение происходит. Скорее всего, int в Вашем компиляторе - 2 байта. А число 95430 в них не влезет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Только что, Alex сказал:

У Вас переполнение происходит. Скорее всего, int в Вашем компиляторе - 2 байта. А число 95430 в них не влезет.

тогда получается использовать другой тип ? лонг ? или как ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
18 минут назад, Alex сказал:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\

Только что попробовал сделать long int и unsigned long int испольщова atoi и atol, результат такой же, как вы сказали, не влезло - переполнение

Изменено пользователем Borodach
Не цитируйте предыдущие посты.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    568

У Вас маленький вопросик и огромная простыня с кодом, в которой нет никакого желания разбираться.
Показывайте код в 2-ух строчках, касающихся конкретной проблемы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Извините. Вот код:
 

#include <mega16.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <delay.h>
#include <alcd.h>
#include <keyboard.h>
#include <math.h>



//__eeprom int FZ, MR;
int flag;
char buf=0;
char FZ_[4];
//char MR_[4];
char kek[4];
int i;
unsigned long int temp_FZ;


 void main(void)
{
	flag = 0;
	lcd_init(16);
	KEYB_Init();
     
	while (1)
      {
             if(flag == 0)
            {
                for( i = 0; i<5; i++)
                {   check_again:
                KEYB_ScanKeyboard();
                buf = KEYB_GetKey();
                if(buf == NULL) goto check_again;
                FZ_[i] = buf;
                lcd_gotoxy(0,1);
                lcd_putsf("FZ");
                lcd_gotoxy(i,0);
                lcd_putchar(FZ_[i]);
                }      
                flag=1;
                  
                 temp_FZ = atol(FZ_);
                 sprintf(kek,"%d", temp_FZ); 
                 
                                  
                 delay_ms(5000);
                 lcd_clear();
            }        
                    
        lcd_gotoxy(0,0);
        lcd_puts(kek);
        
       
 	 }   
}

Вот, все настройки регистров убрал. Как видно,  в основном цикле вайл, в блок иф входит, когда флаг равен нулю. После этого выполняется сканирование клавиатуры и запись чисел в массив, еще отображение записанного числа на дисплее лсд1602, с этим проблем нет. Опрос закончился, выходим из блока фор, делаем флаг равным одному (чтобы при следующем цикле вайл снова не зашел в блок фор), после этого в переменную типа unsigned long int temp_FZ записываем число, которое ввели в массив, предварительно его конвертировав с помощью atoi() или atol(), ну а потом делается действие наоборот, когда это целочисленное число конвертируется с помощью sprintf или itoa в массив символов, то есть строку, и выводиться н экран дисплея. Но на экран дисплея выводится не то число, которое я ввел. Учел то, что вы написали выше насчет инта, провернув это с лонг и ансигнд лонг интом получилось все тоже самое.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
hasl    64

смешались котлеты и мухи
какое нафиг двойное конвертирование

что мешает введенное число умножить на множитель и прибавить к буферу long (посчитайте какой разрядности число может войти в данный тип)

Если это число нужно сохранить, то его просто разбить на 4 байта

В будущем вы как собирались работать с введенным числом?

как собиралась сравнивать к примеру?

 

пссс.

чтобы вывести long Через sprintf в некоторых компиляторах нужно писать вот так "%ld", "%lu"

нужно осторожнее и смотреть какой тип указываете для sprintf и какое число подставляете в качестве параметра

и еще если у вас число не должно быть отрицательным то сразу используйте unsigned

Изменено пользователем hasl

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ну в общем идея такая: датчик холла будет стоять на прерывании, то есть, словил сигнал - переменная инкрементировалась,  когда переменная достигнет 450, то программа запишет в другую переменную единицу, снова 450 еще плюс единица. То есть датчик холла должен считать с насоса литры, 450 сигналов - один литр. Вот я ввел значение с клавы, сделал его интом, и после этого введенное значение будет вычитать из себя каждый литр воды, и выводить на экран. А так как могут быть перебои в сети, чтобы сохранить введенные значения, буду использовать епром, но загнулся на самом простом - конвертации, по- любому ж нужно конвертировать в инт, чтобы внести в епром и делать расчет, а потом снова в строку, что отобразить на дисплее, ибо функция записи в экран число не принимает.

 

То есть вы предлагаете просто по формуле преобразовать массив в число ? якобы int temp = FZ_[0]*10 000 + FZ_[1]* 1000 и тд. Да, это вариант, но как тогда быть если какой-то разряд числа равен нулю ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alexeyslav    642

Надо просто проследить чтобы ВСЕ процедуры у вас в цепочке преобразований работали с long. А то понятное дело, если использовать процедуру вывода которая принимает на входе INT то будет чушь на выходе. Если это простой счетчик, имеет смысл тогда число хранить в BCD-формате, так же его можно  записыфвать в EEPROM. Кстати с коварством EEPROM вы ещё столкнётесь в будущем... у неё ограниченный ресурс записи ячеек. Даже если писать значение каждую минуту, ресурс закончится через несколько лет... потом считывать будете уже не то что записывали. Для таких вещей порой бывает проще использовать микросхему RTC в которой как бонус есть SRAM с батарейным питанием и неограниченным ресурсом - хоть каждый импульс записывай. Одной батарейки обычно хватает на 5...10 лет, и хватает энергии конденсатора даже на время замены батарейки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В общем, каким-то чудом у меня получило конвернтнуть, вывелось так, как и вводилось. Решил сразу вторую настройку написать, в которой уже не 5 разрядов, а 4. Ок,  после первой настройки флаг стал равны единице, переходит во вторую настройку, пишу значение с клавы, ждет, и снова входит во вторую настройку , чтобы ввести значение с клавы. Странно, не могу понять почему происходит это зацикливание, хотя код такой же..

#include <mega16.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <delay.h>
#include <alcd.h>
#include <keyboard.h>
#include <math.h>

__eeprom long int FZ, MR;
int flag;
char buf=0;
char FZ_[5];
char MR_[4];
char kek[5];
char kek1[4];
int t;
int i;
long int temp_FZ,TEMP_FZ1,temp_MR,TEMP_MR1;

 void main(void)
{
flag = 0;
lcd_init(16);
KEYB_Init();
     
while (1)
      {
             if(flag == 0)
            {
                for( i = 0; i<5; i++)
                {   check_again:
                KEYB_ScanKeyboard();
                buf = KEYB_GetKey();
                if(buf == NULL) goto check_again;
                FZ_[i] = buf;
                lcd_gotoxy(0,1);
                lcd_putsf("FZ");
                lcd_gotoxy(i,0);
                lcd_putchar(FZ_[i]);
                }      
                 flag=1;
                 temp_FZ=atol(FZ_);
                 FZ=temp_FZ;
                 TEMP_FZ1=FZ;
                 ltoa(TEMP_FZ1, kek); 
                 delay_ms(5000);
                 lcd_clear();
            }    
       
            if(flag == 1);
            {  
            flag=2;
             for(i=0;i<4;i++)
             {  check_again1:
                KEYB_ScanKeyboard();
                buf = KEYB_GetKey();
                if(buf == NULL) goto check_again1;
                MR_[i] = buf;
                lcd_gotoxy(0,1);
                lcd_putsf("MR");
                lcd_gotoxy(i,0);
                lcd_putchar(MR_[i]);
             }
            
             temp_MR=atol(MR_);
             MR=temp_MR;
             TEMP_MR1=MR;
             ltoa(TEMP_MR1, kek1);
             delay_ms(5000);
             lcd_clear();
            }    

        lcd_clear();
        lcd_gotoxy(0,0);
        lcd_puts(kek);
        lcd_gotoxy(0,1);
        lcd_puts(kek1);
        lcd_clear();

 }     
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    568

Ошибка тут :

2 часа назад, Владислав Бобриков сказал:

if(flag == 1);

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Спасибо)

Убрал точку с запятой, получилось вывести на дисплей две настройки, но только посимвольно, потому что функция lcd_puts() выводит чушь на экран, хотя в нее кидаешь эти два массива с записанными значениями.

Не могли бы ли вы подсказать пожалуйста, как правильно работать с епром ? То есть перед переменной нужно указать eeprom, или __eeprom, тут вроде бы разницы нет. Попробовал с ней поработать, но почему-то после выключения питания программа снова запрашивает ввод данных, хотя по сути должна показывать то, что записано в еепром на экран сразу, ввел условия if(FZ&&MR==NULL) тогда производить настройку;

FZ и MR - переменные епром, в которые записаны значения настроек, после ввода пользователем. Но это почему-то не работает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    568

Не знаю, как это делается в AVR'ах (в частности - в Вашем компиляторе), но сдаётся мне, что одного модификатора  __eeprom не достаточно. Нужно использовать функции записи/чтения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Всем привет !

Извиняюсь, что давно не было, приехал только с каникул. Так вот, подумал, что лучше будет просто записывать значения раз в два часа. На atmega16a 100к циклов перезаписи в eeprom'e, посчитав понял что хватит на 22 года с лишним. Еще посмотрел тесты памяти епром в Интернете, и если верить этим тестам, то AVR`ки делают с запасом, ну грубо говоря, при записи значений раз в 2 часа получим +-4 года.

Возникло пару вопросов:

1) Можно ли сделать таймер, использовав внутренний RC-генератор ? Ну то есть я хочу, чтобы он тикал раз в секунду, или раз в час (хотя это наверное не реально, поэтому просто играясь с переменными можно получить желаемый результат), и будет ли он точным ?  Или лучше использовать внешний кварц для бОльшей точности ?
2) Снова еепром. Почитав пару статей, узнал, что помимо .hex файла в контроллер нужно зашивать еще и .epp, который отвечает непосредственно за еепром. Но это говорили больше про программу Poteus, а не про реальные контроллеры (хотя чтобы загрузить этот .epp в Proteus нужно его преобразовать в .bin) . Так вот, нужно ли зашивать .epp в контроллер, и как это сделать ? (Использую AVRFlash от MicroElectrinica, шью через плату EasyAVR v7).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500

.eep - это начальное состояние EEPROM. Если программа после старта сразу ожидает наличие каких-то данных в EEPROM - надо прошивать этот файл. Если программа сама все в EEPROM записывает, что нужно, этот файл можно выкинуть.

Раз в секунду или даже раз в 2 секунды "тикает" WDT - можно сделать на нем. Точность кране не высокая, температурнозависимая, но зато большой период. А в промежутках можно глубоко спать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

.epp зашивать так же, как и .hex ? то есть сначала .hex, а потом .epp, или последовательность не важна ?

Лол
Это как же на вочдоге сделать по переполнению, если он потом просто будет перезагружать контроллер ?)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500

Как правило, всякие "студии" сами занют, в каком порядке все прошивать. Принципиально, пока RST удерживается в низком уровне, можно шить как угодно при любых условиях.

7 минут назад, Владислав Бобриков сказал:

Это как же на вочдоге сделать по переполнению, если он потом просто будет перезагружать контроллер

Вот именно так и сделать. В некоторых моделях МК есть прерывание по WDT, а в тех, у которых такого варианта нет, можно просто после сброса понять, что было - подача питания, сброс от кнопки или сброс от WDT из глубокого сна, и соответственно поступать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
4 минуты назад, ARV сказал:

В некоторых моделях МК есть прерывание по WDT, а в тех, у которых такого варианта нет, можно просто после сброса понять, что было - подача питания, сброс от кнопки или сброс от WDT из глубокого сна, и соответственно поступать.

Теперь вот интересно, меня троллят сейчас, или нет))

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500

Если вам не хочется читать документацию, вам придется верить мне на слово.

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
  
uint8_t __attribute__((noinit)) port;
  
int main(void){
  DDRB = 255;
  PORTB = port;
  port <<= 1;
  if(!port) port = 1;
  wdt_enable(WDTO_2S);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_mode();
}

Вот пример кода "бегущего огня" на порту B, основанный на WDT, который сбрасывает МК каждые 2 секунды (медленноватый бег, конечно). После первого запуска может возникнуть бег не одного огонька, а хаотического количества, но спустя 8 пересбросов все будет нормально (это мне лень было писать красиво).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alexeyslav    642

У WDT есть несколько режимов работы, это описывается в даташите на контроллер. Он может генерировать прерывание, без сброса на первый раз, и если в прерывании собаку не успокоить, то второе срабатывание вызовет аппаратный сброс. И есть классический режим работы - сразу же на первом срабатывании аппаратный сброс. В старых контроллерах есть только второй режим.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

То есть, если установить только один бит WDIE, то собака будет работать в режиме прерывания по истечению, допустим, секунды ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 437

у мну вопрос вот этот гоуту

 check_again1:
                KEYB_ScanKeyboard();
                buf = KEYB_GetKey();
                if(buf == NULL) goto check_again1;

почему бы не написать по нормальному

do { 
     KEYB_ScanKeyboard();
     buf = KEYB_GetKey();
   } while(buf == NULL);

??????

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    568

@IMXO , ничего, в принципе, зазорного тут нет. Всё приходит с опытом годами ... :)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 437

какбе да, особенно когда пользуют копипаст и "случайно" теряется индекс метки , и прога улетает в другой конец кода и разрушением стека , а так да ничего зазорного.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ваша публикация должна быть проверена модератором

Гость
Вы не авторизованы. Если у вас есть аккаунт, пожалуйста, войдите.
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Восстановить форматирование

  Разрешено не более 75 смайлов.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

Загрузка...