Я пытаюсь узнать о встроенном программировании, поэтому я купил arduino mega2560. Мне не очень понравилась среда разработки Arduino (потому что она кажется слишком простой и абстрактной, по крайней мере, для меня :)), поэтому я начал программировать ее, используя чистый C и набор инструментов avr (avrdude и подобные). Я пытаюсь написать программу, которая читает ваше имя, а затем мигает светодиодом для каждого символа вашего имени.
Основная схема программы такова:
Проблемы (обозначенные **) заключаются в том, что я не вижу вывод printf, а fgetc запрашивает ввод. Как это исправить?
Спасибо!
Обновлено: вот код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <util/delay.h>
#ifndef STDIN
#define STDIN 0
#endif
int main(void) {
char *name = (char *)malloc((int)NULL);
char c;
int cnt;
int i;
cnt = 1;
DDRB |= (1 << DDB7);
printf("Enter your name: ");
while ((c = fgetc(STDIN)) != '\n') {
name = (char *)realloc(name, cnt);
strncat(name, &c, 1);
cnt++;
}
for (i = 0; i < strlen(name); ++i) {
PORTB |= (1 << PB7);
_delay_ms(1000);
PORTB &= ~(1 << PB7);
}
return 0;
}
@AndrejsCainikovs Вы имеете в виду добавление кода? Что еще я должен добавить?
Шаг 1: char c; --> int c;, чтобы правильно сохранить 257 различных возвращаемых значений fgetc().
strncat(name, &c, 1);
плохо, так как name
не указывает на строку.
Программы Arduino обычно используют последовательный порт для ввода/вывода. Можете ли вы скомпилировать этот код без ошибок или предупреждений? У вас есть библиотека, которая реализует printf и fgetc? Динамическое выделение памяти может привести к проблемам во встроенных системах.
@Bodo Да, у меня нет ошибок. Я включил stdio.h, который реализует printf и fgetc.
Не имеет отношения к вашему вопросу, но динамическое выделение памяти и возврат из main() не совсем подходят для вашей платформы. Возврат из main в автономной среде определяется реализацией - ваша среда выполнения может бесконечно зацикливаться, сбрасываться или просто запускаться неизвестно куда и демонстрировать неопределенное поведение.
(char *)malloc((int)NULL)
это ерунда. И использование malloc на MCU вообще бессмысленно. Почему мне не следует использовать динамическое выделение памяти во встраиваемых системах?Пожалуйста, объясните, что вы ожидаете от своей ардуино (где вы печатаете и как вводите данные) и что вместо этого происходит. Я предполагаю, что у вас нет консольного терминала, подключенного к вашему Arduino, так где же ожидается ввод и где должен быть напечатан ваш вывод?
Передача нулевого указателя на fgetc() вряд ли даст вам желаемые результаты.
char *name = (char *)malloc((int)NULL);
в этом нет никакого смысла. Вы в основном выделили 0 байт для имени. Также не приводить результаты malloc.malloc
. Это не персональный компьютер, и вам нужно забыть о многих «больших» компьютерных вещах;strncat(name, &c, 1);
это странно. И это не сработает, так как ни один из ваших параметров не является строкой C. Вы знаете, что такое последний параметр?strlen
не будет работать, так как вы не передаете строку C.Мне не очень понравилась IDE arduino (потому что она кажется слишком базовый и абстрактный, по крайней мере для меня :))
Я думаю, что на вашем уровне знаний это правильное направление. Arduino - это библиотеки C++ +, и это не «просто»
Да у меня ошибок нет. Я включил stdio.h, который реализует printf и fgetc
Добавление заголовочного файла не решает проблему. Вам нужно написать несколько низкоуровневых функций, чтобы stdio функции начали работать. stdout и stdin по умолчанию не обмениваются данными через UART. Подробнее: https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#ga4c04da4953607fa5fa4d3908fecde449
«Также не приводить результаты malloc». Это слизь для любителей Arduino, так что на самом деле это C++.
@Lundin он сказал, что не использует Arduino
Разве эти пользовательские библиотеки не являются частью библиотек Arduino? Или это просто что-то, поставляемое Atmel/Microchip?
@Lundin Я считаю, что avr-gcc поддерживается Microchip. Но (поскольку нет OP или файловой системы) они предоставляют только заглушки функций ввода-вывода (такие же, как ветка ARM). Вам нужно подключить его к реальному оборудованию
Ну 1. вообще не имеет смысла, не значит что это UB или ошибка.... Инициализирует NULL в name, так что хорошо когда доходит до realloc(). 2. Зачем ему реализовывать библиотеку malloc для этой платформы, если он не может ее использовать? Тебе не кажется, что ты слишком остро реагируешь? не должно существовать реализации malloc, разве он не получит ошибку компоновщика во время сборки? Я немного сбит с толку, поскольку я разрабатываю встроенный, и я вижу, что если у вас нет какой-либо доступной функции, вы получаете ошибку связывания.
Потому что у вас очень ограниченный ресурс, и эта крошечная память будет мгновенно фрагментирована.
Библиотека stdio для микроконтроллеров, где stdout, stdin вообще не должны существовать, а там, где они есть, они обязательно зависят от аппаратного обеспечения и доступного ввода-вывода и являются дизайнерскими решениями разработчика проекта, а не ответственностью разработчика библиотеки.
Обычно для встроенной библиотеки будет слой переноса или «склеивания», чтобы сопоставить библиотеку с аппаратными зависимостями, и если вы не предоставите необходимые функции, они будут связаны с общими «ничего не делающими» заглушками.
Конкретные переопределения функций-заглушек, которые вам необходимо предоставить, будут зависеть от цепочки инструментов и, в частности, от используемой вами библиотеки C. И средства, с помощью которых вы их «устанавливаете», различаются в зависимости от цепочки инструментов. Некоторые используют «слабые ссылки», которые вы просто предоставляете переопределениям с той же сигнатурой, другие используют структуры с указателями функций на низкоуровневые функции ввода-вывода. Например, если вы используете AVR Libc , вам просто нужно предоставить функции get-char / put-char и использовать их в FILE структуре, назначенной потокам stdin, stdout, как описано в документации.
Например:
#include <stdio.h>
// Output character to stdout device
static int std_putchar(char c, FILE *stream)
{
...
return 0;
}
// Input character from stdin device
static int std_getchar(char c, FILE *stream)
{
...
return rxchar ;
}
// Create stdio stream
static FILE stdio_stream = FDEV_SETUP_STREAM( std_putchar, std_getchar,
_FDEV_SETUP_RW ) ;
int main(void)
{
stdout = &stdio_stream ;
stdin = &stdio_stream ;
stderr = &stdio_stream ;
printf( "System Start - hello\n") ;
// Echo input
for(;;)
{
putchar( getchar() ) ;
}
}
Вы можете реализовать функции символьного ввода-вывода низкого уровня любым способом, который подходит для вашей системы, использовать UART, клавиатуру, ЖК-дисплей, интерфейс отладчика - что угодно.
Arduino fgetc() и printf() обычно считывают и печатают из последовательного порта, который вы должны инициализировать, чтобы установить скорость передачи данных, четность, стоповые биты и размер символов для работы (и вы, вероятно, не знаете об этом). Обычно для этого требуется запустить эмуляцию терминала последовательного соединения (и настроить его с той же скоростью передачи данных, четностью, стоповыми битами и размером символов), чтобы наблюдать за вводом/выводом Arduino. затем вы загружаете программное обеспечение в Arduino, запускаете эмуляцию терминала и нажимаете кнопку сброса (чтобы снова загрузить Arduino)
Неясно, ожидаете ли вы, что ваш вывод будет отправлен, и вы ничего об этом не говорите, поэтому я, вероятно, слишком предполагаю, что у вас неправильное представление о вашей среде, я могу ошибаться, но вы не упомянули ни одного из характеристики выше (любая из них настроена неправильно и вы увидите хлам, либо вообще ничего). Ваш arduino не является частью вашего компьютера, поэтому не ожидайте, что его выходные данные будут напрямую открывать всплывающее окно на вашем компьютере и отображать его.
Я сожалею, что не рассказал немного больше о том, как настроить Arduino (и компьютер, чтобы он делал то, что вы хотите), но на YouTube есть много видеоуроков, которые покажут вам, как это сделать. Есть очень хорошие туториалы от Ben Eater (просто поищите их) и множество проектов (не тривиальных, их много)
ИМХО, вы слишком упростили свою цель и начали с гораздо более сложного проекта, чем вы можете просто проглотить одним выстрелом.
Покажите нам, что вы пробовали. В вашем вопросе не хватает деталей и деталей реализации.