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

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

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

Сообщение WiseLord »

Да, я тоже подобным образом делал:
Спойлер

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

...
#define CONCAT(x,y)			x ## y

#define DDR(x)				CONCAT(DDR,x)
#define PORT(x)				CONCAT(PORT,x)
#define PIN(x)				CONCAT(PIN,x)

/* KS0108 Data port*/
#define KS0108_D0			B
#define KS0108_D0_LINE		(1<<0)
#define KS0108_D1			B
#define KS0108_D1_LINE		(1<<1)
#define KS0108_D2			B
#define KS0108_D2_LINE		(1<<2)
#define KS0108_D3			B
#define KS0108_D3_LINE		(1<<3)
#define KS0108_D4			B
#define KS0108_D4_LINE		(1<<4)
#define KS0108_D5			B
#define KS0108_D5_LINE		(1<<5)
#define KS0108_D6			B
#define KS0108_D6_LINE		(1<<6)
#define KS0108_D7			B
#define KS0108_D7_LINE		(1<<7)
...

...
static void ks0108SetPort(uint8_t data)
{
	if (data & (1<<0)) PORT(KS0108_D0) |= KS0108_D0_LINE; else PORT(KS0108_D0) &= ~KS0108_D0_LINE;
	if (data & (1<<1)) PORT(KS0108_D1) |= KS0108_D1_LINE; else PORT(KS0108_D1) &= ~KS0108_D1_LINE;
	if (data & (1<<2)) PORT(KS0108_D2) |= KS0108_D2_LINE; else PORT(KS0108_D2) &= ~KS0108_D2_LINE;
	if (data & (1<<3)) PORT(KS0108_D3) |= KS0108_D3_LINE; else PORT(KS0108_D3) &= ~KS0108_D3_LINE;
	if (data & (1<<4)) PORT(KS0108_D4) |= KS0108_D4_LINE; else PORT(KS0108_D4) &= ~KS0108_D4_LINE;
	if (data & (1<<5)) PORT(KS0108_D5) |= KS0108_D5_LINE; else PORT(KS0108_D5) &= ~KS0108_D5_LINE;
	if (data & (1<<6)) PORT(KS0108_D6) |= KS0108_D6_LINE; else PORT(KS0108_D6) &= ~KS0108_D6_LINE;
	if (data & (1<<7)) PORT(KS0108_D7) |= KS0108_D7_LINE; else PORT(KS0108_D7) &= ~KS0108_D7_LINE;

	return;
}

static void ks0108SetDdr(uint8_t data)
{
	if (data & (1<<0)) DDR(KS0108_D0) |= KS0108_D0_LINE; else DDR(KS0108_D0) &= ~KS0108_D0_LINE;
	if (data & (1<<1)) DDR(KS0108_D1) |= KS0108_D1_LINE; else DDR(KS0108_D1) &= ~KS0108_D1_LINE;
	if (data & (1<<2)) DDR(KS0108_D2) |= KS0108_D2_LINE; else DDR(KS0108_D2) &= ~KS0108_D2_LINE;
	if (data & (1<<3)) DDR(KS0108_D3) |= KS0108_D3_LINE; else DDR(KS0108_D3) &= ~KS0108_D3_LINE;
	if (data & (1<<4)) DDR(KS0108_D4) |= KS0108_D4_LINE; else DDR(KS0108_D4) &= ~KS0108_D4_LINE;
	if (data & (1<<5)) DDR(KS0108_D5) |= KS0108_D5_LINE; else DDR(KS0108_D5) &= ~KS0108_D5_LINE;
	if (data & (1<<6)) DDR(KS0108_D6) |= KS0108_D6_LINE; else DDR(KS0108_D6) &= ~KS0108_D6_LINE;
	if (data & (1<<7)) DDR(KS0108_D7) |= KS0108_D7_LINE; else DDR(KS0108_D7) &= ~KS0108_D7_LINE;

	return;
}
Идею с макросами типа PORT() вроде давно у ARV подсмотрел, сейчас почти везде у себя применяю.
Реклама
Rtmip
Держит паяльник хвостом
Сообщения: 963
Зарегистрирован: Чт апр 03, 2014 23:16:55
Откуда: Россия

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

Сообщение Rtmip »

Здравствуйте!
Появились вопросы некоторые.
Вопрос про функцию printf, компилятор Keil:
Предположим есть такая конструкция

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

 unsigned char ADC_rezult()
{
    unsigned char adc_data;
..........
    return adc_data;
}
...........
  while (1)
   {    	 
    	ADC_rezult();
	printf ("%u\n", ADC_rezult()); 
   }
вывод в терминал результата.
Почему в терминале вместо одного байта выводится два?
Как правильно надо сделать?
Я попробовал добавить в программу следующее:

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

volatile unsigned char result; 		//переменная для данных
...
result = ADC_rezult(); 		//результат с АЦП
printf ("%d\n",(unsigned int)result);
Так все работает правильно, но правильно ли это?
Еще вопрос, как лучше, но не очень заумно(понятно для начинающего) "отзеркалить" байт?
Например, есть байт А0Н, а надо получить 05Н? С помощью дополнительных переменных двубайтовых
и сдвигов в них 8 раз это разумно или можно иначе? :dont_know:
Реклама
Аватара пользователя
-Valerius-
Встал на лапы
Сообщения: 99
Зарегистрирован: Сб янв 12, 2013 22:43:10
Откуда: Москва

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

Сообщение -Valerius- »

WiseLord писал(а):Да, я тоже подобным образом делал:
Идею с макросами типа PORT() вроде давно у ARV подсмотрел, сейчас почти везде у себя применяю.
Спасибо большое, по-моему это то что нужно!
Буду разбираться. :beer:
spongebob
Грызет канифоль
Сообщения: 289
Зарегистрирован: Пт мар 20, 2009 12:25:47
Откуда: Ivanovo
Контактная информация:

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

Сообщение spongebob »

подскажите по вопросу сохранения структуры в eeprom и получении из eeprom структуры
есть структура

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

struct _stflag {
   unsigned char step : 4;
   unsigned char work : 1;
   unsigned char mode : 1;
} stflag;
как видно - она занимает 6 бит
нужно её сохранить в ячейку eeprom, а потом (при необходимости) получить обратно

есть функции для работы с eeprom:
ee_write(unsigned char adr, unsigned char dat)
unsigned char ee_read(unsigned char adr)
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

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

Сообщение Gudd-Head »

spongebob писал(а):как видно - она занимает 48 бит
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18629
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

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

Сообщение ARV »

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

unsigned char *ptr = (void*)&stflag;

ee_write(0, *ptr); // запись структуры в EEPROM с адреса 0x0000

*ptr = ee_read(0); // чтение той самой структуры из EEPROM c 0-го адреса
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Реклама
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

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

Сообщение isx »

Здравствуйте!
Подскажите пожалуйста, как мне после обработки внешнего прерывания вернуться в начало основного цикла (main). Нужно возвращаться именно в начало, не зависимо от того, какая строка выполнялась до прерывания.
Я бы просто в конце прерывания поставил GOTO с маркером в начале функции, но кейл ругается на него...
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

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

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

isx писал(а): Я бы просто в конце прерывания поставил GOTO с маркером в начале функции, но кейл ругается на него...
И правильно делает. Ибо goto возможно только в пределах одного блока кода. Видимо, это сделали специально для защиты от подобных "финтов".
Переход на вектор прерывания - это не обычное изменение адресной точки программы (типа goto), а полноценный вызов функции, с применением стека. По этому, возвращаться из него в любое место программы - практически не возможно.
Вы лучше скажите откуда появилась такая потребность, авось посоветуем чего-нибудь более традиционное...
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

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

Сообщение isx »

В основном цикле у меня несколько формул, которые из набора переменных вычисляют одно значение. Это значение должно быть максимально точным в каждый конкретные момент времени. Некоторые переменные изменяются в прерывании по событию. Нужно чтобы при изменении любой переменной расчет происходил с самого начала основного цикла (и если прерывание произошло в середине основного цикла, то после выхода из прерывания необходимо вернуться в начало основного цикла и произвести расчет с уже измененными переменными).
И еще вопрос созрел. Есть у меня набор значений как положительных, так и отрицательных. Как высчитать разрыв между двумя конкретными значениями? К примеру имеем два значения 1 и 1, разрыв между ними = 0. Теперь другие, 0 и 1, разрыв между ними = 1. А теперь самое интересное, значения -1 и 1, разрыв между ними = 2. Как такое на СИ реализовать не пойму... :dont_know:
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

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

Сообщение WiseLord »

Я бы посоветовал в прерывании просто устанавливать какой-нибудь флаг, а в начале главного цикла его сбрасывать. Результат вычислений не принимать, если флаг установлен. Для более быстрого перехода в начало цикла (если вычисления сложные и длительные) расставить проверки типа if (flag) continue; внутри цикла:
Спойлер

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

volatile uint8_t isrFlag;

ISR () {
  isrFlag = 1;
}

int main() {
  ...
  while (1) {
    isrFlag = 0;
    formula1();
    if (isrFlag)
      continue;
    formula2();
    if (isrFlag)
      continue;
    formula3();
    if (isrFlag)
      continue;
    processResult();
  }
}
Как такое на СИ реализовать не пойму
Вычесть одно из другого, очевидно.
Последний раз редактировалось WiseLord Вт авг 04, 2015 23:08:51, всего редактировалось 1 раз.
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

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

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

Если Вам нужно выполнять вычисления только по обновлению переменных, то сделайте процессы синхронизированными, по тем же флагам. В прерывании переменную обновили, взвели флаг. В майне проверяете флаг и выполняете вычисления.
По второму вопросу. Это же обычное вычитание :)

ЗЫ: Упс, опоздал. Слишком медленно печатаю :))
Последний раз редактировалось Аlex Вт авг 04, 2015 23:09:56, всего редактировалось 1 раз.
Причина: -
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

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

Сообщение isx »

Аlex писал(а):По второму вопросу. Это же обычное вычитание
Да, но вот только иногда получаются отрицательные значения, и приходится добавлять еще if и менять знак в этом случае. Думал может по-проще алгоритм есть, но похоже нет :) .
WiseLord писал(а):Я бы посоветовал в прерывании просто устанавливать какой-нибудь флаг,
Напрямую получается никак нельзя сделать? Тогда попробуем флаг...
Спасибо за ответы :)
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

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

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

isx писал(а): Да, но вот только иногда получаются отрицательные значения,
Нужно вычитать из большего меньшее, тогда отрицательных значений никогда не получится.
Что-то типа:

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

int diff(int a, int b){
  return a>b ? a-b : b-a;
}
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

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

Сообщение isx »

Точно... Так можно выбросить умножение на -1. Еще раз благодарю :) .
spongebob
Грызет канифоль
Сообщения: 289
Зарегистрирован: Пт мар 20, 2009 12:25:47
Откуда: Ivanovo
Контактная информация:

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

Сообщение spongebob »

а подскажите ещё по записи/чтению структур в/из eeprom
на этот раз уже большая структура

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

struct _state {
   unsigned char temp[5];
   unsigned char time[9];
} state;
14 байт.
функции записи/чтения работают с одним байтом
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

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

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

Перебирайте все байты по одному в цикле и пишите их по-очереди в еепром.
Не вижу проблем... :dont_know:

Как пример - http://forum.chipmk.ru/index.php/topic/ ... -с-eeprom/
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

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

Сообщение WiseLord »

Для avr-gcc в avr-libc есть функции eeprom_read_block() и eeprom_write_block() (а также eeprom_update_block() и eeprom_update_block()), позволяющие читать/писать большое количество байтов.
Поэтому всё будет достаточно просто. Например, для записи этой структуры по адресу 0xA0 вызвать её как-то так:

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

eeprom_update_block(&state, (void*)(0xA0), sizeof(state));
spongebob
Грызет канифоль
Сообщения: 289
Зарегистрирован: Пт мар 20, 2009 12:25:47
Откуда: Ivanovo
Контактная информация:

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

Сообщение spongebob »

Аlex писал(а):Как пример - http://forum.chipmk.ru/index.php/topic/ ... -с-eeprom/
взял вариант без прерываний
сначала пихал ему указатель, не то
потом просто писал ee_write(0,state) и ee_read(0,state)
получаю предупреждения "illegal conversion between pointer types", но считывает/записывает правильно
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

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

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

Замените

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

#define ee_write(adr,p_d) _ee_write(adr,&p_d,sizeof(p_d))
#define ee_read(adr,p_d) _ee_read(adr,&p_d,sizeof(p_d))
на

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

#define ee_write(adr,p_d) _ee_write(adr,(char *)&p_d,sizeof(p_d))
#define ee_read(adr,p_d) _ee_read(adr,(char *)&p_d,sizeof(p_d))
kalobyte
Друг Кота
Сообщения: 13796
Зарегистрирован: Чт сен 20, 2007 14:08:00

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

Сообщение kalobyte »

внезапно я :tea:
вчера ковырял одно гавно на пхп и столкнулся с интерфейсами
пхп давно учил и забил, а тут какая-то новая херня
быдлокниги не читал, посмотрел ролик какого-то какляцкого школьника

правильно ли я понял, что интерфейсы это просто перечень методов, которые потом будут реализованы в разных классах и будут делать какие-то штуки, но в основном коде надо использовать готовое название метода, которое есть интерфейс?
или например я сам могу переопределить этот метод в своем приложении

интерфейсы используются в фабриках, насколько я понял из видоса про фабрики
тематические ответы только в форуме, в приват не пишите
Ответить

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