LINUX.ORG.RU

Обращение к портам ввода/вывода на C

 ,


0

4

Есть плата, хочу использовать порты DIO в качестве GPIO, на этой картинке таблица с их адресами взятая с сайта производителя. Так же производитель предоставил отрывок кода для работы с ними, который я к сожалению не понимаю:

#include <stdio.h>
#include <sys/io.h>
int main() {
    if (ioperm(0x7A,4,1)<0){
        printf(“Error\n”);
        return -1;
    }
    //set pins0 to 3 to inputs
    ioval=inb(0x7a);
    ioval= ioval & 0xFE;
    outb(ioval, 0x7A);
 
    return 0;
}

Для начала хочу научиться, как минимум работать с ними как в Arduino (т.е. снимать и подавать с них напряжение).

Относительно кода, я так представляю, что функция ioperm(0x7A,4,1) просто запрашивает разрешение на работу с определенным портом, но как адресоваться на конкретную ножку я не понял, по картинке адрес 0x7B для DIO1 и ножек 0-7, как включить\отключить например 3? Что делает эта связка ioval= ioval & 0xFE; мне не ясно совсем



Последнее исправление: GeneralProger (всего исправлений: 4)

Что делает эта связка ioval= ioval & 0xFE; мне не ясно совсем

Снимает младший бит.

// set bit
val |= 1<<n;
// clear bit
val &= ~(1<<n)

В твоём примере n=0: ~(1<<0) == ~1 == 0xFE == b11111110

bwhatever & b11111110 = bwhateve0

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 3)

У тебя ж в таблице все по-русски расписано! Т.к. обычно везде по умолчанию порты настроены на вход, то чтобы дергать ногой, тебе сначала надо изменить режим ноги на выход. За это отвечает бит 0 регистра 7A, т.е. тебе надо сделать сначала:

    //set pins0 to 3 to outputs
    ioval = inb(0x7a);
    ioval |= 1;
    outb(ioval, 0x7a);
Дальше. Нога 3 — это третий бит (т.е. 0x04) регистра 7B. Чтобы ею дернуть, можно сделать так:
    //set DIO1_3
    ioval = inb(0x7b);
    ioval |= 0x04;
    outb(ioval, 0x7b);
    sleep(1);
    // clear DIO1_3
    ioval = inb(0x7b); // do this, because state of other pins could be changed outside!
    ioval &= ~0x04;
    outb(ioval, 0x7b);

anonymous
()
Ответ на: комментарий от anonymous

Спасибо, но почему-то срабатывает только единожды. В чем может быть дело? Т.е. по умолчанию ножка под напряжением, при выполнении программы она выключается, далее ничего не происходит, ни в цикле, ни при новом запуске программы, помогает только перезагрузка

#include <stdio.h>
#include <sys/io.h>
int main() {
	if (ioperm(0x7a,4,1)<0){
		printf("Error\n");
		return -1;
	}
	unsigned int wrt = inb(0x7a);
	printf("RUN WITH: %d\n", wrt);
    wrt |= 1;
    outb(wrt, 0x7a);
	printf("  changed: %d\n", wrt);

	int i = 0;
	while (i < 5) {
		printf("Cycle: %d\n", i);
		
		// HIGH
		unsigned int gpio_high = inb(0x7b);
		printf("  next high: %d (%d)\n", gpio_high, inb(0x7a));
		gpio_high |= 0x04;
		outb(gpio_high, 0x7b);
		sleep(2);
		
		// LOW
		unsigned int gpio_low = inb(0x7b);
		printf("  next low: %d (%d)\n", gpio_low, inb(0x7a));
		gpio_low &= ~0x04;
		outb(gpio_low, 0x7b);
		sleep(2);
		
		i++;
	}
	return 0;
}

GeneralProger
() автор топика
Ответ на: комментарий от GeneralProger

В принципе вопрос снимаю, вместо не совсем понятных мне склеек:

ioval = inb(0x7b);
    ioval |= 0x04;
    outb(ioval, 0x7b);
Решил использовать очевидные мне:
outb(0b00010000, 0x7b);
И все заработало

GeneralProger
() автор топика
Ответ на: комментарий от anonymous

Нахожу, я на момент написания сообщения использовал 0b00011000 и как раз собирался вычислить с какой стороны идет отсчет, думал с левой, на деле с правой))

GeneralProger
() автор топика
Ответ на: комментарий от GeneralProger

Если собираешься с битами работать, стоит наверно разобраться-таки с битовыми оперциями.
Ничего сложного там нет, обычная булева логика, только применяется к каждому биту по отдельности.

Пример на 4х битах:
IJKL = ABCD & EFGH
где:
I = A & E
J = B & F
K = C & G
L = D & H

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.