Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Аватара пользователя
Shuspano
Грызет канифоль
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Re: Вопросы по С/С++ (СИ)

Сообщение Shuspano »

Добрый день.
Столкнулся с такой ошибкой в подпрограмме setup():

Код: Выделить всё

D:\avr\hc164.c:17:2: error: stray '\302' in program
  PORT┬ |=  (1 << PB0);
  ^
сама подпрограмма:

Код: Выделить всё

void setup(void)
	{
	DDRB  |=  (1 << PB0)|(1 << PB1)|(1 << PB2);
	DDRD  &= ~(1 << PD7);
	DDRD  |=  (1 << PD6);
	PORTВ |=  (1 << PB0); 
	}

Ощущается состояние обутости в лыжи. Ну вот что тут может быть не так?
Реклама
NStorm
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Re: Вопросы по С/С++ (СИ)

Сообщение NStorm »

*фэйспалм.джпг*

Вам же в ошибке явно написано в чем проблема. Не PORTB у вас там, а PORTВ написано. Не видите разницы? А она есть. Не надо кириллицей пытаться замещать латинские буквы с таким же написанием.
Реклама
Аватара пользователя
Shuspano
Грызет канифоль
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Re: Вопросы по С/С++ (СИ)

Сообщение Shuspano »

Упс...Извините. Ну я это не специально.
Часто avr-gcc указывает на ошибки там где их нету, или их описание настолько лапидарно, что в целом, ни о чем. Уже привык.
NStorm
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Re: Вопросы по С/С++ (СИ)

Сообщение NStorm »

Ну видно же, что вместо PORTB в выводе комилятора уже написано "PORT". И выше текст о недопустимом символе. Это и должно было на мысль натолкнуть.
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

Shuspano писал(а):Часто avr-gcc указывает на ошибки там где их нету
с роду такого не было! примеры в студию
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Реклама
Аватара пользователя
Shuspano
Грызет канифоль
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Re: Вопросы по С/С++ (СИ)

Сообщение Shuspano »

[uquote="ARV",url="/forum/viewtopic.php?p=3838320#p3838320"]
Shuspano писал(а):Часто avr-gcc указывает на ошибки там где их нету
с роду такого не было! примеры в студию[/uquote]

Ну вот например:

Код: Выделить всё

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
  }
  ^
Строка 99 = закрывающая скобка подпрограммы main()

весь код:
Спойлер

Код: Выделить всё

#define F_CPU 8000000UL

#define	sclock	PB2
#define sdata	PB0
#define latch	PB4
#define rdata	PB3

#include <avr/io.h>
#include <util/delay.h>

void setup(void)
	{
	DDRB  |=  (1 << sdata)|(1 << sclock)|(1 << latch);
	DDRB  &= ~(1 << rdata);
	}

void sh_pulse(void)
	{
	PORTB |=  (1 << sclock);
	PORTB &= ~(1 << sclock);
	}

void hc165latch(void)
	{
	PORTB &= ~(1 << latch);
	PORTB |=  (1 << latch);
	}
	
void hc595latch(void)
	{
	PORTB |=  (1 << latch);
	PORTB &= ~(1 << latch);

void hc595send(unsigned char hc595data)
	{
	PORTB |= (1 << latch);
	
	int i; 
	for (i=0; i<8; i++)
		{
		if (hc595data & 0x80)
			{
			PORTB |= (1 << sdata);
			}
		else
			{
			PORTB &= ~(1 << sdata);
			}
		hc595data = hc595data << 1;
		sh_pulse();
		}
	hc595latch();
	}

unsigned char hc165read()
	{
	PORTB &= ~(1 << latch);
	
	unsigned char hc165data;
	int y;
	hc165latch();
	for (y=0; y<8; y++)
		{
		hc165data = hc165data << 1;
		if (PINB & (1 << rdata))
			{
			hc165data |=  (1 << 0);
			}
		else
			{
			hc165data &= ~(1 << 0);
			}
		sh_pulse();
		}
	return(hc165data);
	}
		
/*
void ledflash(void)
	{
	PORTD |=  (1 << ledpin);
	_delay_ms (5);
	PORTD &= ~(1 << ledpin);
	_delay_ms (5);
	}
*/

void main(void)
	{
	setup();
	while(1)
		{
		unsigned char j;
		j = ~hc165read();
		hc595send(j);
		ledflash();
		_delay_ms(50);
		}
	}
 
если это не компилятор выделывается, то что это?
Реклама
NStorm
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Re: Вопросы по С/С++ (СИ)

Сообщение NStorm »

Shuspano, ошибка состоит из 2х строк, а не одной. Над сторокой со строкой ошибки, есть еще одна строка =/
d:\avr\hc164.c: In function 'hc595latch':
Сразу должно смутить, что функция hc595latch у нас идет до 99ой строки. Смотрим - и у функции пропущена закрывающая }. И конечно же компилятор считает, что эта функция продолжается до конца файла и резко обрывается, не закрываясь должным образом. Потому что компилятор прежде чем разбирать саму функцию, ищет её начало и конец по { }. И не находит в вашем случае.
На самом деле ошибка вполне очевидная, если понимать это.
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение Аlex »

Мало того, ещё и ledflash закоменчен. Хотя пытаются его вызвать :facepalm:

Добавлено after 1 minute 30 seconds:
[uquote="Shuspano",url="/forum/viewtopic.php?p=3839044#p3839044"]если это не компилятор выделывается, то что это?[/uquote]Руки, сударь, руки ...

PS: Всегда удивляли вот такие компиляторвиноват'оры. Конечно, а ктож ещё, не они же сами :)))
Аватара пользователя
Shuspano
Грызет канифоль
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Re: Вопросы по С/С++ (СИ)

Сообщение Shuspano »

[uquote="NStorm",url="/forum/viewtopic.php?p=3839049#p3839049"]если понимать это.[/uquote]
Это если понимать. Я к сожалению, этого не понимаю, и для меня это сообщение выглядит так: в огороде бузина, а в Киеве дядька.
Аlex писал(а):Мало того, ещё и ledflash закоменчен
Таки да, но я тогда еще до этой ошибки еще не дошел :)

еще такой вопрос. Вот эти подпрограммы, или функции в Си... как их там. Нельзя ли сделать чтоб было как в ассемблере - где хочу, там и вхожу
Например (ассемблер MCS-51) можно сделать так:

Код: Выделить всё

label0: mov, A, R0
label1: setb C
label2: cpl A
           inc DPTR
           ret
Тут я могу вызвать подпрограмму с любой метки, без разницы с какой. А можно ли сделать тоже самое в сишных void-ах?
NStorm
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Re: Вопросы по С/С++ (СИ)

Сообщение NStorm »

Не в void'ах, а в функциях. Void лишь возвращаемое значение функции. Сделать-то можно, банально хотя бы так:

Код: Выделить всё

void foo(int bar) {
  if (bar == 0)
    do0();
  if (bar <= 1)
    do1();
  do2();
}
Только лучше прекращать мыслить ассемблером и смотреть как делают на С. При должном подходе "входить в функцию в любом месте" в С не нужно.
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Вопросы по С/С++ (СИ)

Сообщение ПростоНуб »

Shuspano, так как С выделяет память для локальных переменных из стека при входе в функцию, у функции может быть только одна точка входа. При этом, вполне реально добиться от оптимизатора именно такого кода, создав в одном файле три функции label0(), label1() и label2() и объявив две последние inline.
Аватара пользователя
Shuspano
Грызет канифоль
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Re: Вопросы по С/С++ (СИ)

Сообщение Shuspano »

NStorm писал(а): Сделать-то можно, банально хотя бы так:
ПростоНуб писал(а):При этом, вполне реально добиться от оптимизатора именно такого кода, создав в одном файле три функции label0(), label1() и label2() и объявив две последние inline.
Спасибо большое!
От ассемблера избавится довольно непросто. Заметил, что прежде чем что-то добавить в программу, я сначала представляю как это сделать на ассемблере (и уже почти написал в голове) и только потом иду гуглить как это в Си делать.
NStorm
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Re: Вопросы по С/С++ (СИ)

Сообщение NStorm »

я сначала представляю как это сделать на ассемблере
А вот это порочная практика ) Именно она обычно и не дает использовать С правильно и в полной мере. Я серьезно в данном случае. Возможности языка куда больше, чтобы применять прямолинейный подход асма.

Я хоть и написал выше пример, на деле такое в C обычно редко нужно. Обычно логика работы по-другому делается просто.
Atz
Встал на лапы
Сообщения: 87
Зарегистрирован: Ср сен 16, 2009 22:44:40

Re: Вопросы по С/С++ (СИ)

Сообщение Atz »

Нельзя ли сделать чтоб было как в ассемблере - где хочу, там и вхожу
Считается плохой практикой, но конечно, можно. Гуглите "оператор 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. В редакторе всё станет красивое, а компилировать можно из командной строки.
Аватара пользователя
Shuspano
Грызет канифоль
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Re: Вопросы по С/С++ (СИ)

Сообщение Shuspano »

Добрый день.
Решил немного разнообразить свое поделие, и приделать к нему индикатор 1604. Подключить, естественно, к выходам регистра 74hc595. Использовать в 4-битном режиме. И чтоб отправить символ на индикатор, необходимо произвести обмен старшей тетрады (полубайта) между двух переменных типа unsigned char, при этом не испортив младшую тетраду. В ассемблере MCS-51 это делается как два пальца об асфальт: существует инструкция XCHD. В Си похоже ничего такого нету. Пробовал логическими операциями - не получается, не возможно никак заставить, чтоб это делалось только с 4-мя битами.
Что тут можно предпринять?
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Shuspano писал(а):необходимо произвести обмен старшей тетрады (полубайта) между двух переменных типа unsigned char, при этом не испортив младшую тетраду
Десять раз перечитал и не понял, что нужно сделать
Аватара пользователя
Shuspano
Грызет канифоль
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Re: Вопросы по С/С++ (СИ)

Сообщение Shuspano »

WiseLord писал(а):Десять раз перечитал и не понял, что нужно сделать
есть два байта А и Б. Байт состоит из двух тетрад. Мне нужно старшую тетраду байта А переставить в старшую тетраду байта Б, при этом не испортив его младшую тетраду.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

Код: Выделить всё

unsigned char A, B;

// старшую тетраду байта А переставить в старшую тетраду байта Б
B = (B & 0x0F) | (A & 0xF0);
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Shuspano
Грызет канифоль
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Re: Вопросы по С/С++ (СИ)

Сообщение Shuspano »

Спасибо! Можно продолжать.
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Shuspano, Вообще, как я понимаю, Если Вы пытаетесь завести KS0066 дисплей через 74РС595, то у Вас конфигурация следующая:
D7..D4 дисплея подключены к выходам 7..4 74РС595
BL (подсветка), E (строб), RW (запись/чтение), RS (команда/данные) - подключены к выходам 3..0 соответственно.

Вот вам идея:
- есть лишь специальная глобальная переменная (portData), которая (и только она) отправляется в 595-ку.
- есть лишь одна функция отправки этих данных (sendPortData)

Любые операции записи в дисплей приводятся к этой одной функции, и не более того. И весь базовый код будет очень простым:
Спойлер

Код: Выделить всё

#define BL_LINE  (1<<3) // подсветка на 3 линии порта
#define E_LINE   (1<<2) // строб на 2 линии порта
#define RW_LINE  (1<<1) // RW на 1 линии порта
#define RS_LINE  (1<<0) // RS на 0 линии порта

static uint8_t portData = 0x00;

static void sendPortData(uint8_t data) {
  // тут пишем функцию отправки байта data
}

static void writeStrob()
{
    sendPortData(portData | E_LINE);    // К имеющимся данным добавляем E
    sendPortData(portData);             // И убираем снова
}

static void ks0066WritePort(uint8_t data)
{
    _delay_us(100);
    portData &= ~RW_LINE;          // RW опускаем

    portdata &= 0xF0;              // Чистим младшую тетраду
    portData |= (data & 0x0F);     // Пишем младшую тетраду из младшей тетрады байта
    writeStrob();                  // Реально пишем данные в 595

    portdata &= 0xF0;              // Чистим младшую тетраду
    portData |= (data >> 4);       // Пишем старшую тетраду из старшей тетрады байта
    writeStrob();                  // Реально пишем данные в 595
}

static void ks0066WriteCommand(uint8_t command)
{
    portData &= ~RS_LINE;       // RS опускаем
    ks0066WritePort(command);
}

void ks0066WriteData(uint8_t data)
{
    portData |= RS_LINE;        // RS поднимаем
    ks0066WritePort(data);
}
Я подобным образом работал с дисплеем, подключенным через I²C расширитель PCF8574 - достаточно популярный вариант подключения.

P.S. чуть подправил код и комментарии
Ответить

Вернуться в «Разные вопросы по МК»