Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.83/18: Рейтинг темы: голосов - 18, средняя оценка - 4.83
0 / 0 / 0
Регистрация: 24.07.2017
Сообщений: 6
1

AVR работа с указателями

24.07.2017, 22:30. Показов 3657. Ответов 16
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Помогите разобраться с кодом.
Нужно считать строку из порта и отправить ее обратно.
Отправить строку в порт - все ок. Работает.
Проблема с чтением. Решил в функцию передавать указатель.
Объявляю указатель, строку*, присваиваю указатель адрес строки, передаю указатель функции. Читаю строку. Присваиваю ее значение по адресу из указателя. Для проверки вывожу в порт (выводится, все Ок.). Вывожу в порт строку* - выводит мусор. Помогите понять где я напортачил.
Код:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//=======
 
void SerialReadString (char *ppstr[255]) {
    
    char str[255];
    int numOfDataR=0;
    char tmpCh =' ';    
    
    
    while(tmpCh!=0x0D) 
                    //Принемаем данные пока не придет возврат коретки. 
                    {
                    tmpCh=SerialReadChar();
                    if (numOfDataR==255) {numOfDataR=0;};
                    str[numOfDataR++]=tmpCh;  
                    }
    *ppstr=str; 
    SerialSendStringLn(*ppstr); // проверка вывода. зесь все ок. 
    numOfDataR=0; 
}
//================
 
/*******************************************************************/
#define F_CPU 16000000UL
#include <avr/delay.h>
#include "USORT_lib_atm328.h"
 
int main(void)
{
    char str[255]; 
    char *pstr[255];
    SerialIni ();
    SerialSendStringLn("Hi, it's a test of new serial library. Is it looks Ok?");
    SerialSendString("input>>");
    
    pstr[0]=&str[0];    
    while (1){
        SerialReadString(pstr); 
        SerialSendString(str);
    }
    return 0;   
}
 
/*******************************************************************/
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
24.07.2017, 22:30
Ответы с готовыми решениями:

Странная работа Keil с указателями
Ранее я работал с С только в Visual Studyo. Она работает вот так: Visual Studyochar globalArray =...

Работа с указателями
#include &lt;iostream&gt; #include &lt;conio.h&gt; using namespace std; void fun(int *p) { int...

Работа с указателями
Условие: Одно из возможных представлений &quot;длинного&quot; текста - это разделить его на участки...

Работа с указателями
Написать программу работы с указателями. LONG *p1; ULONG x = 5; LONG y = -1; LONG *p2 = p1 +...

16
1976 / 1275 / 130
Регистрация: 04.01.2010
Сообщений: 4,607
24.07.2017, 23:04 2
1) Дикая путаница с указателями и массивами указателей... Ну да ладно - если это еще и работает, то это просто чудо). Компилятор наверняка матерится на чем свет стоит - но это же не важно, если компилируется, верно?
2) Проблема кроется в настройках компилятора (и в самом компиляторе). В функцию вы передаете указатель на строку-константу, когда как функция работает исключительно с переменными (то есть RAM). В случае с AVR это разные вещи. Из FLASH данные читаются совсем не так, как из RAM.

ЗЫ: вот за что я люблю CodeVision, так это за то, что в нем заранее можно сказать компилеру, куда ему класть переменную или константу - в RAM, FLASH или EEPROM. и компилер сам все сожрет (там внутри еще и с указателями путаница) и заработает сходу.

ТС, читайте сообщения компилятора внимательнее...
1
210 / 163 / 36
Регистрация: 15.11.2012
Сообщений: 788
26.07.2017, 22:46 3
Лучший ответ Сообщение было отмечено kurakste как решение

Решение

У вас каша в голове про строки и указатели - это нормально -), для начала.

В процедуре main:
строка *pstr[255] организует вам 255 указателей, а не указатель на строку в 255 символов.
pstr не инициализирован (указывает куда-то, вообще говоря на NULL). Напишите так:
char str[255]; // это ваша строка
char *pstr; // это указатель, но его надо инициализировать
pstr=str; // вот теперь он указывает куда надо.
Вот только не ясно, почему нельзя в параметре функции SerialReadString указать просто str (видимо, компилятор говорит об ошибке -)).

Теперь о функции. Напишите заголовок так:
void SerialReadString (char *ppstr)
Таким образом, вы передаете адрес строки, в которую вам надо поместить принятую строку.
Уберите char str[255] - он не нужен, ведь вы будете заполнять строку, адрес которой дали при вызове.
Вместо str[numOfDataR++]=tmpCh; напишите *(ppstr+numOfDataR++)=tmpCh;
*ppstr=str; - не нужна.
не забудьте, что любая строка должна заканчиваться нулем - в конце процедуры напишите *(ppstr+numOfDataR)=0;
Иначе сначала будет вывод полезный, а дальше - то, что идет дальше по памяти, пока там все-таки не встретится 0. На компе можно и мегабайт мусора так получить вместо (точнее, в дополнение) десятка полезных байт -).
1
0 / 0 / 0
Регистрация: 24.07.2017
Сообщений: 6
27.07.2017, 22:00  [ТС] 4
Большое спасибо!
Помогло. Но статью про указатели прочел еще раз :-)
Есть еще вопрос по этому коду. Как я себе понимал эти строки:
SerialSendStringLn("Hi, it's a test of new serial library. Is it looks Ok?");
SerialSendString("input>>");

Должны выводиться один раз при старте программы. Но они выводятся при каждом подключении к порту. Как это работает?
0
210 / 163 / 36
Регистрация: 15.11.2012
Сообщений: 788
27.07.2017, 22:41 5
Должны выводится один раз. Вывод здесь можно сделать только один - контроллер перезапускается. Причины - вопрос отдельный, может быть много вариантов. Первый - при подключении к порту вы подаете питание, при отключении - убираете. Второй - сброс контроллера при подключении (наводки, емкости параллельно питанию контроллера в устройстве, которое вы подключаете).
Теоретически есть еще один вариант. Попробуйте вместо
if (numOfDataR==255)
написать
if (numOfDataR==253). Это может изменить ситуацию.
Я с mega328 не работал, но на довольно старых еще контроллерах at90s8515 (это тоже ядро AVR, позже он стал называться mega8515), сталкивался с тем, что они сбрасывались даже от касания платы пинцетом. В последующем была замена на mega16, с которым (на той же фактически плате - там только несколько ног изменено) подобных проблем не было. Однако осадочек остался -)).
1
1976 / 1275 / 130
Регистрация: 04.01.2010
Сообщений: 4,607
28.07.2017, 00:00 6
Цитата Сообщение от alexey6689 Посмотреть сообщение
старых еще контроллерах at90s8515
одним из отличий at90 и меги стало наличие подтяжки ресета. В принципе, очень много вопросов было у меня из-за этого.
Особенно, когда "на коленке".

ТС, какой у Вас чип? Я еле нашел, откуда вам подсказывают насчет "меги328", но имя сторонней библы мне лично ни о чем не говорит. Учитывая ваши действия с памятью, вполне вероятно, вы можете выпадать банально в проблемы со стеком, например. Ничего еще не сделав, вы "легко" выделяете 1кб памяти, что в случае с имбеддед - "это просто праздник какой-то". 1КБ, это роскошь, которой обзавидуются многие разработчики программ для МК .
Хотя, я тоже склоняюсь к описанной ув. alexey6689 выше возможной проблеме/
1
210 / 163 / 36
Регистрация: 15.11.2012
Сообщений: 788
28.07.2017, 00:16 7
Ну, думаю и есть mega328.
Памяти там 2 КБ, а выделяется 255 байт. Жирненько, но для сброса мало. Тем более что написано, что сброс происходит в момент подключения внешнего устройства. Очевидно, при уже подключенном устройстве все работает.

Подтяжка дела не решала - у меня всегда был и резистор на питание, и кондюк. Переход на mega8515 ничего не изменил.
Коренным образом дело поменялось после перехода на mega16.
1
0 / 0 / 0
Регистрация: 24.07.2017
Сообщений: 6
28.07.2017, 21:51  [ТС] 8
Это действительно atmega328p на плате ардуино уно. Взял поиграть и что-то меня увлекло.
Я посмотрел сейчас осциллографом питание - вроде нет никаких изменений при подключении к порту.
Посоветуйте алгоритм как понять в чем глюк.
Условия следующие: Плата ардуино запитана от USB. Тот который штатно стоит на плате. Подключаюсь к ней через программу Terminal v1,9b К плате ничего не подключено.
Мог я что-то напортачить при инициализации usarta? код:

C
1
2
3
4
5
6
7
8
9
10
void SerialIni (void) {
    
    // выставляю скорость с удвоение в 115 200
    UBRR0H = 0;
    UBRR0L =103;
    
    UCSR0A = (0b00000010); //выставляю U2X0
    UCSR0B = (0b11011000); //разрешаю использовнаие прерываний по приему и передачи
    UCSR0C = (0b00000110); // 7,6 ассинхонный режим (00);4,5 -   выключит проверку на четность (00),3 - один стопбит (0); 2,1 - включаем 8 битную посылку (11);
}
Добавлено через 10 минут
Я так понимаю, что чего-то не понимаю. Я думал что есть у меня 2к памят и это размер переменных + констант которые которые я могу использовать. Прочитав сообщение, задумался о том, что стек тоже лежит в этой памяти. Я вроде стек не использую, но наверное вызов функций с++ сопровождается работой со стеком. А сколько он под него выделил и как расходует не ясно. Потом переменные в функциях живут только в функциях, но может так случится, что при запуске функции не останется место под ее переменные. По идеи компилятор должен был зарезервировать место под это заранее. С другой стороны бестоковый расход памяти. Интересно как он себя ведет?
Я в правильную сторону думаю? Или что-то еще упустил?
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
28.07.2017, 22:00 9
kurakste, используйте теги форматирования кода
0
210 / 163 / 36
Регистрация: 15.11.2012
Сообщений: 788
29.07.2017, 03:02 10
Лучший ответ Сообщение было отмечено kurakste как решение

Решение

Да, стек тоже в памяти. Я не знаю, какой у вас компилятор, я работаю в IAR, там размер стека задается в файле .xcl линковщика. Если на стек мало места - возможны странности. Но в моей практике это всегда приводило к зависанию, не к перезапуску.
Вот насчет констант это правда. И на мой взгляд это какой-то косяк. Я задаю константную строку, и она занимает место в оперативной памяти. Приходилось использовать для таких строк атрибут flash, однако работа с ней при этом возможна только специальными функциями, которые умеют из памяти программ брать данные (например, sprintf_P вместо sprintf) - последствия использования гарвардской архитектуры.
Если вас напрягает постоянное выделение памяти под переменные в функции, задавайте их с ключевым словом static. Тогда в отчете компилятора (точнее, линковщика) вы сможете узнать сколько именно байт требует ваша программа и данные.

Добавлено через 2 минуты
А проверку я бы сделал так: в начале программы зажигайте светодиодик какой-нибудь (там они наверняка есть), а через секунду скажем гасите его. Программу для работы с RS при этом можно (и даже нужно) убрать - ведь задача понять это она виновата или электрика. Далее подключайте разъемы, постучите по плате чем-нибудь металлическим (касаясь токоведущих частей, только замыкать их не надо -).
Если контроллер сбрасывается, светодиодик будет мигать.

Добавлено через 7 минут
Как бы вы не задали режим RS, он просто либо будет работать, либо не будет. К сбросу это приводить не должно в любом случае.
Однако если линия RxD контроллера не притянута к плюсу, то при отключении вашего разъема контроллер может начать непрерывный прием байта 0 (там будет вылезать ошибка отсутствия стоп-бита, но неизвестно как ведут себя ваши программы-обработчики, да и из самого даташита не очень ясно, будет ли USORT выдавать это байт как принятый несмотря на ошибку). Правда, при корректных обработчиках это тоже к сбросу не приведет.

Добавлено через 1 минуту
А у вас есть принципиальная схема вашей ардуины, а так же устройства, которое вы втыкаете? Посмотреть бы.

Добавлено через 1 минуту
Так... Подождите, что вы понимаете под словами "подключаюсь и отключаюсь"? Что вы подключаете и отключаете?
1
0 / 0 / 0
Регистрация: 24.07.2017
Сообщений: 6
29.07.2017, 08:13  [ТС] 11
Похоже не ясно выразился. Ардуина постоянно подключена через USB разъем. Я ее питаю и прошиваю пока через него.
Под подключать я имел ввиду нажатия кнопки коннект в терминальной программе (пробовал в разных).

Добавлено через 1 минуту
компилятор- atmel studio. Скачал с их сайта.
0
210 / 163 / 36
Регистрация: 15.11.2012
Сообщений: 788
29.07.2017, 19:13 12
Тогда что-то странное действительно.
Покажите текущий вариант вашей программы?
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
29.07.2017, 19:18 13
Цитата Сообщение от kurakste Посмотреть сообщение
Ардуина постоянно подключена через USB разъем.
Цитата Сообщение от kurakste Посмотреть сообщение
int main(void)
что то не стыкуется
0
0 / 0 / 0
Регистрация: 24.07.2017
Сообщений: 6
29.07.2017, 21:10  [ТС] 14
Вот и я не пойму как это работает. Код я переписал, но эффект тот же:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <avr/io.h>
 
static int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,_FDEV_SETUP_WRITE);
 
void SerialIni (void) {
    
    // выставляю скорость с удвоением в 115 200
    UBRR0H = 0;
    UBRR0L =103;
    
    UCSR0A = (0b00000010); //выставляю U2X0
    UCSR0B = (0b11011000); //разрешаю использование прерываний по приему и передачи
    UCSR0C = (0b00000110); // 7,6 ассинхонный режим (00);4,5 -   выключит проверку на четность (00),3 - один стопбит (0); 2,1 - включаем 8 битную посылку (11);
}
 
 
int uart_putchar(char c, FILE *stream)
{
    if (c == '\n')
    uart_putchar('\r', stream);
    loop_until_bit_is_set(UCSR0A, UDRE0);
    UDR0 = c;
    return 0;
}
 
int main(void)
{
    SerialIni();
    stdout = &mystdout;
    printf("Hello, world!\n");
    return 0;
}
0
210 / 163 / 36
Регистрация: 15.11.2012
Сообщений: 788
29.07.2017, 21:59 15
Что-то вас бросает из одной крайности в другую. Долго пытался понять, что вообще делает эта программа и почему она вообще должна выводить что-то кроме Hello, world!
Также я не знаю что будет, если выходить из контроллерной процедуры main. Никогда так не делал. Выполнение начнется сначала?
0
0 / 0 / 0
Регистрация: 24.07.2017
Сообщений: 6
29.07.2017, 23:34  [ТС] 16
Я дописал включение выключение светодиода внутри этого кода.
Программа работает как должна - один раз отрабатывает и все.
А вот терминальные программы выводят сообщения при каждом подключении.
Получается система? то что выдал контролер записала в какой-то буфер и теперь каждый раз выдает эту строчку. Странно.

Теперь переписал код:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#define F_CPU 16000000UL
#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
 
 
static int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,_FDEV_SETUP_WRITE);
 
void SerialIni (void) {
    
    // выставляю скорость с удвоением в 115 200
    UBRR0H = 0;
    UBRR0L =103;
    
    UCSR0A = (0b00000010); //выставляю U2X0
    UCSR0B = (0b11011000); //разрешаю использование прерываний по приему и передачи
    UCSR0C = (0b00000110); // 7,6 ассинхонный режим (00);4,5 -   выключит проверку на четность (00),3 - один стопбит (0); 2,1 - включаем 8 битную посылку (11);
}
 
 
int uart_putchar(char c, FILE *stream)
{
    if (c == '\n')
    uart_putchar('\r', stream);
    loop_until_bit_is_set(UCSR0A, UDRE0);
    UDR0 = c;
    return 0;
}
 
int main(void)
{
    unsigned int a =0;
    DDRB |= 1<<5; // настраиваю ногу на вывод. 
    PORTB |=1<<5; // включаю свет
    _delay_ms(1000); 
    
    
    SerialIni();
    stdout = &mystdout;
    printf("Hello, world!\n");
    
 
    
    while (1){
        printf("%d \n",a);
        PORTB &=~(1<<5);
        _delay_ms(500);
        PORTB |=1<<5; // включаю свет
        _delay_ms(500);
        a++;
        
    }
    return 0;
}
Запускаю- при каждом подключении терминальной программой к порту выводится приветствие и отсчет идет сначала. Треш какой-то.

Добавлено через 1 час 27 минут
Я был не прав. При подключении терминала к ардуине она перезагружается.
Погуглил - нашел ответ:
Именно USB-serial контроллер Arduino перезагружает МК каждый раз, когда терминальная программа (в т.ч. Serial monitor, встроенный в ПО Arduino IDE) устанавливает соединение. Реализовано это следующим образом: у USB-serial контроллера вывод DTR (Data Terminal Ready) связан с выводом RESET. Если программа, работающая с виртуальным последовательным портом, использует DTR, то при установке соединения МК перезагружается.
0
210 / 163 / 36
Регистрация: 15.11.2012
Сообщений: 788
30.07.2017, 05:19 17
Да уж... Впрочем, просмотр принципиальной схемы решил бы этот вопрос, думаю, существенно быстрее.
0
30.07.2017, 05:19
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.07.2017, 05:19
Помогаю со студенческими работами здесь

Работа с указателями
13. Дан файл Assort, содержащий сведения об игрушках: указывается назва¬ние игрушки, ее стоимость в...

работа с указателями
#include &lt;iostream&gt; using namespace std; int main() { char *res=&quot;&quot;; res=&quot;1&quot;; ...

Работа с указателями
Нужно чтобы при каждом попадании &quot;1&quot;, в введенной строке выводилось сообщение на экран. ...

Работа с указателями
Доброго времени суток! Прошу помощи в решении очень интересной задачи. Перепробовал все свои...

Работа с указателями
Задана матрица чисел и заданы 2 массива указателей. Настроить первый массив указателей на...

Работа с указателями
Здравствуйте, товарищи. Есть библиотека ddcom32.dll, которую я подключаю в свой проект и использую...

работа с указателями
Помогите решить задачу в С++ (я в этом начиющий): 1)Из положительных значений двух целочисленных...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru