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

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

Recommended Posts

Ребята, всем привет !
Вот стоит задача, с матричной клавиатуры считать 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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
Только что, Alex сказал:

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

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

Share this post


Link to post
Share on other sites

Приглашаем на вебинар «Новинки и уникальные решения Molex. На что обратить внимание и почему»

15 апреля приглашаем на вебинар, который будет интересен разработчикам и инженерам-схемотехникам, интересующимся тенденциями рынка, новыми перспективными решениями для соединений «провод-провод», «провод-плата», «плата-плата». Для инженеров КИПиА и IT будут освещены уникальные решения Molex для «удлинения» интерфейсов HDMI, DisplayPort и USB даже в условиях сильного зашумления, а также семейство бесконтактных датчиков Contrinex. Помимо этого, будет уделено внимание дальнейшему развитию направления антенн, где Molex имеет ряд интересных и уникальных решений.

Подробнее

18 минут назад, Alex сказал:

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

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

Edited by Borodach
Не цитируйте предыдущие посты.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
                     

Как снизить потери при включении силового ключа: простая схема управления скоростью нарастания

Снижение потерь на переключения в силовых электронных системах, например, в приводах, зачастую противоречит требованиям ЭМС и ограничивается таким параметром как скорость нарастания напряжения. Простой способ решения, предлагаемый Infineon – параллельное использование двух традиционных драйверов.

Читать статью

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

#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 в массив символов, то есть строку, и выводиться н экран дисплея. Но на экран дисплея выводится не то число, которое я ввел. Учел то, что вы написали выше насчет инта, провернув это с лонг и ансигнд лонг интом получилось все тоже самое.

Share this post


Link to post
Share on other sites

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

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

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

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

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

 

пссс.

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

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

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

Edited by hasl

Share this post


Link to post
Share on other sites

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

 

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

Share this post


Link to post
Share on other sites

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


Учение - изучение правил. Опыт - изучение исключений.

Share this post


Link to post
Share on other sites

В общем, каким-то чудом у меня получило конвернтнуть, вывелось так, как и вводилось. Решил сразу вторую настройку написать, в которой уже не 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();

 }     
}

 

Share this post


Link to post
Share on other sites

Ошибка тут :

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

if(flag == 1);

Share this post


Link to post
Share on other sites

Спасибо)

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

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Всем привет !

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

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

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

Share this post


Link to post
Share on other sites

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

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


Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

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

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

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


Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Share this post


Link to post
Share on other sites
4 минуты назад, ARV сказал:

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

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

Share this post


Link to post
Share on other sites

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

#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 пересбросов все будет нормально (это мне лень было писать красиво).


Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Share this post


Link to post
Share on other sites

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


Учение - изучение правил. Опыт - изучение исключений.

Share this post


Link to post
Share on other sites

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

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

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

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

??????

Share this post


Link to post
Share on other sites

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

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...