Вам же в ошибке явно написано в чем проблема. Не PORTB у вас там, а PORTВ написано. Не видите разницы? А она есть. Не надо кириллицей пытаться замещать латинские буквы с таким же написанием.
Упс...Извините. Ну я это не специально.
Часто avr-gcc указывает на ошибки там где их нету, или их описание настолько лапидарно, что в целом, ни о чем. Уже привык.
D:\comp\avr8-gnu-toolchain\bin>avr-gcc -Os -mmcu=attiny13a -o d:\avr\hc164-13a.e
lf d:\avr\hc164.c
d:\avr\hc164.c: In function 'hc595latch':
d:\avr\hc164.c:99:2: error: expected declaration or statement at end of input
}
^
Shuspano, ошибка состоит из 2х строк, а не одной. Над сторокой со строкой ошибки, есть еще одна строка =/
d:\avr\hc164.c: In function 'hc595latch':
Сразу должно смутить, что функция hc595latch у нас идет до 99ой строки. Смотрим - и у функции пропущена закрывающая }. И конечно же компилятор считает, что эта функция продолжается до конца файла и резко обрывается, не закрываясь должным образом. Потому что компилятор прежде чем разбирать саму функцию, ищет её начало и конец по { }. И не находит в вашем случае.
На самом деле ошибка вполне очевидная, если понимать это.
Мало того, ещё и ledflash закоменчен. Хотя пытаются его вызвать
Добавлено after 1 minute 30 seconds:
[uquote="Shuspano",url="/forum/viewtopic.php?p=3839044#p3839044"]если это не компилятор выделывается, то что это?[/uquote]Руки, сударь, руки ...
PS: Всегда удивляли вот такие компиляторвиноват'оры. Конечно, а ктож ещё, не они же сами
[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)
Любые операции записи в дисплей приводятся к этой одной функции, и не более того. И весь базовый код будет очень простым:
Спойлер