[uquote="NStorm",url="/forum/viewtopic.php?p=3839049#p3839049"]если понимать это.[/uquote]
Это если понимать. Я к сожалению, этого не понимаю, и для меня это сообщение выглядит так: в огороде бузина, а в Киеве дядька.
Аlex писал(а):Мало того, ещё и ledflash закоменчен
Таки да, но я тогда еще до этой ошибки еще не дошел
еще такой вопрос. Вот эти подпрограммы, или функции в Си... как их там. Нельзя ли сделать чтоб было как в ассемблере - где хочу, там и вхожу
Например (ассемблер MCS-51) можно сделать так:
Shuspano, так как С выделяет память для локальных переменных из стека при входе в функцию, у функции может быть только одна точка входа. При этом, вполне реально добиться от оптимизатора именно такого кода, создав в одном файле три функции label0(), label1() и label2() и объявив две последние inline.
NStorm писал(а): Сделать-то можно, банально хотя бы так:
ПростоНуб писал(а):При этом, вполне реально добиться от оптимизатора именно такого кода, создав в одном файле три функции label0(), label1() и label2() и объявив две последние inline.
Спасибо большое!
От ассемблера избавится довольно непросто. Заметил, что прежде чем что-то добавить в программу, я сначала представляю как это сделать на ассемблере (и уже почти написал в голове) и только потом иду гуглить как это в Си делать.
я сначала представляю как это сделать на ассемблере
А вот это порочная практика ) Именно она обычно и не дает использовать С правильно и в полной мере. Я серьезно в данном случае. Возможности языка куда больше, чтобы применять прямолинейный подход асма.
Я хоть и написал выше пример, на деле такое в C обычно редко нужно. Обычно логика работы по-другому делается просто.
Нельзя ли сделать чтоб было как в ассемблере - где хочу, там и вхожу
Считается плохой практикой, но конечно, можно. Гуглите "оператор goto в языке Си".
я сначала представляю как это сделать на ассемблере
Делайте всё, что вы делали обычно на ассемблере, только внутри одной функции на Си, никогда не выходя за её пределы — и будем вам "щастье". Это называется "инкапсуляция". А вот практика создания сложных циклов на метках как раз и считается порочной, потому что потом не разобраться в коде.
В применении к конкретному примеру: не надо пытаться входить в середину функции по метке и тем более переходить по ней из одной функции в середину другой. Надо активно выдумывать новые функции и вызывать их имена (как подпрограммы) из тех мест, где вы обычно делаете переход по метке. В этом случае goto рассасывается и становится не нужен.
Историческая заметка: СпойлерВ паскале были процедуры и функции — те и другие являлись подпрограммами, у кого-то были возращаемые значения и параметры, а у кого-то нет. Понятно, что весь этот набор сводится к одним только функциям, поэтому в Си только они и есть.
После этого у вас 100% возникнет вопрос «как сохранять переменные при смене функций». В языке Си вам придётся делать глобальные переменные или структуры и передавать указатели на них в параметры функций. В С++ можно создавать класс: всем функциям этого класса видны все переменные своего класса.
Кусочек вашего примера на упрощённом псевдокоде, похожем на С++: Спойлер
struct MyObjects // во множественном числе, потому что это ещё не сам объект, а их тип.
{
MyObjects() // конструктор, вызывается автоматически при создании объекта класса
{
setup();
}
protected:
void setup();
private:
// описание всех переменных, например "int DDRB;"
public:
void my_function(); // доступные для вызова снаружи функции класса (его интерфейс).
}
; // здесь кое-что новое для вас: точка с запятой после фигурной скобки оканчивает класс.
void MyObjects::setup()
{
DDRB |= (1 << sdata)|(1 << sclock)|(1 << latch);
DDRB &= ~(1 << rdata);
}
void MyObjects::my_function()
{
// do something wrong, fix it and do something again :)
}
int main(/* параметры главной функции не используем, просто опишем их тип */int, char*[] )
{
MyObjects object_one;
MyObjects object_two;
// всё: setup вызван у обоих объектов автоматически и оба объекта — независимые.
// можно создавать свои функции и вызывать их так: object_one.my_function();
// глобальная область видимости при этом остаётся чистая, а каждый объект имеет
// по своему набору переменных в памяти.
return 0;
}
Добавлено after 13 minutes 40 seconds:
добавлено: если есть сложности с чтением кода или проблемы зрением, то возьмите Far Manager версии 1.xx (не 2 и не 3), найдите к нему плагин HighLighter и покрасьте себе код по-цветастее, редактируя настройки этого плагина в его папочке и каждый раз перезапуская Far Manager. В редакторе всё станет красивое, а компилировать можно из командной строки.
Добрый день.
Решил немного разнообразить свое поделие, и приделать к нему индикатор 1604. Подключить, естественно, к выходам регистра 74hc595. Использовать в 4-битном режиме. И чтоб отправить символ на индикатор, необходимо произвести обмен старшей тетрады (полубайта) между двух переменных типа unsigned char, при этом не испортив младшую тетраду. В ассемблере MCS-51 это делается как два пальца об асфальт: существует инструкция XCHD. В Си похоже ничего такого нету. Пробовал логическими операциями - не получается, не возможно никак заставить, чтоб это делалось только с 4-мя битами.
Что тут можно предпринять?
Shuspano писал(а):необходимо произвести обмен старшей тетрады (полубайта) между двух переменных типа unsigned char, при этом не испортив младшую тетраду
Десять раз перечитал и не понял, что нужно сделать
WiseLord писал(а):Десять раз перечитал и не понял, что нужно сделать
есть два байта А и Б. Байт состоит из двух тетрад. Мне нужно старшую тетраду байта А переставить в старшую тетраду байта Б, при этом не испортив его младшую тетраду.
Shuspano, Вообще, как я понимаю, Если Вы пытаетесь завести KS0066 дисплей через 74РС595, то у Вас конфигурация следующая:
D7..D4 дисплея подключены к выходам 7..4 74РС595
BL (подсветка), E (строб), RW (запись/чтение), RS (команда/данные) - подключены к выходам 3..0 соответственно.
Вот вам идея:
- есть лишь специальная глобальная переменная (portData), которая (и только она) отправляется в 595-ку.
- есть лишь одна функция отправки этих данных (sendPortData)
Любые операции записи в дисплей приводятся к этой одной функции, и не более того. И весь базовый код будет очень простым:
Спойлер
Похоже я прогневал кого-то из программистских богов.
Пытался выделить функцию hc595send() в отдельный файл, чтоб спокойно потестить логические функции - она отказалась работать. Притащил осциллограф, чтоб посмотреть чего выдает аттини13, а после измерений он отказался прошиваться через усбасп. Сходил за большим программатором (top-3000), вставил тиньку, сбросил на заводские фузы, все шьется, все хорошо. Подключил к усбасп - не шьется. Опять в большой программатор, подключаю его к компу - венда выдает синего.
Кажется, на сегодня хватит.
Shuspano писал(а):Явно что-то не так, но при этом (что необычно) все работает так, как хотел.
работает - потому что не ошибка, а варнинг.
а не так то, что dptr у вас "указатель на символ" (т.е. на ОЗУ), а массив lcd_data - это "массив неизменяемых символов во FLASH", то есть типы указателей не одинаковы, вот и предупреждает.
совет вам: избавляйтесь от PROGMEM, заменяйте это на корректное и правильное const __flash (вы ж не WinAVR используете? новые версии так могут):
Спасибо!
Не, у меня блокнот, avr-gcc, и дудка. Я просто знаю как это делать на ассемблере: строка размещается директивой DB, адрес строки в16-битный регистр-указатель, а там - MOVC или LPM. Я погуглил, нашел кое что у DI HALT, и решил что PROGMEM - это аналог этой директивы.
Shuspano писал(а):Не, у меня блокнот, avr-gcc, и дудка.
и чо? WinAVR - это довольно древняя версия avr-gcc. если у вас свежая версия - пользуйтесь тем, что я рекомендовал.
Shuspano писал(а):Я просто знаю как это делать на ассемблере
забудьте! если взялись за Си, пользуйтесь средствами Си, чтобы быстрее войти в струю. разумеется, запаситесь справочником каким-нибудь по основным определениям, правилам, функциям и т.п. для Си. и реализовывайте свои алгоритмы уже этими средствами.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
D:\avr>make func_test.c attiny13a
func_test.c: In function 'main':
func_test.c:123:2: error: '__flash' specified for auto variable 'lcd_data'
const __flash unsigned char lcd_data[] = "Hello, Radiokot";
^
avr-objcopy: 'func_test.elf': No such file
вынесите этот массив в область глобальных переменных, то есть за пределы функции, вот и вся проблема.
Добавлено after 1 minute 15 seconds:
кстати, для символьных строк правильнее применять просто char, а не unsigned char - все стандартные функции рассчитаны именно на char - будете ловить варнинги...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...