сайт для палких паяльників
  • Facebook
  • Twitter
  • Google Plus
  • Add to favorites
  • Email
  • Print
  • RSS

В предыдущей статье мы рассмотрели работу STM32 с шиной I2C в качестве Мастера. То есть, он был ведущий и опрашивал датчик. Теперь сделаем так, чтобы STM32 был Slave-ом и отвечал на запросы, то есть сам работал как датчик. Мы выделим 255 байт памяти под регистры с адресами от 0 до 0xFF, и позволим Мастеру в них писать/читать. А чтобы пример был не таким простым, сделаем из нашего STM32, еще и аналого-цифровой преобразователь с интерфейсом I2C. ADC будет обрабатывать 8 каналов. Результаты преобразований контроллер будет отдавать Мастеру при чтении из регистров. Поскольку результат преобразования ADC занимает 12 бит, нам потребуется 2 регистра (2 байта) на каждый канал ADC.

Весь функционал, касающийся I2C Slave, находится в файлах i2c_slave.h, i2c_slave.c. Скачать пример можно здесь: STM32. скачать примеры

i2c_slave.h содержит настройки:

I2CSLAVE_ADDR – адрес нашего устройства;

ADC_ADDR_START – начальный адрес регистров, которые отвечают за результаты преобразований ADC.

В файле i2c_slave.c нас больше всего интересуют функции get_i2c1_ram и set_i2c1_ram. Функция get_i2c1_ram отвечает за считывание данных из регистров. Она возвращает данные с указанного адреса, которые отдаются Мастеру. В нашем случае данные считываются из массива i2c1_ram, но, если Мастер спрашивает адреса регистров из диапазона отведенного для результатов ADC, то отправляются данные преобразований ADC.

get_i2c1_ram:

uint8_t get_i2c1_ram(uint8_t adr) {
	//ADC data
	if ((ADC_ADDR_START <= adr) & (adr < ADC_ADDR_START + ADC_CHANNELS*2)) {
		return ADCBuffer[adr - ADC_ADDR_START];
	}
	else {
		// Other addresses
		return i2c1_ram[adr];
	}
}

Функция set_i2c1_ram – записывает данные принятые от Мастера в регистры с указанным адресом. В нашем случае данные просто записываются в массив i2c1_ram. Но это не обязательно. Вы можете, например, добавить проверку, и, когда на определенный адрес приходит определенное число, выполнить какие-то действия. Таким образом, Вы сможете подавать микроконтроллеру разные команды.

set_i2c1_ram:

void set_i2c1_ram(uint8_t adr, uint8_t val) {
	i2c1_ram[adr] = val;
	return;
}

Инициализация достаточно проста:

int main(void)
{
	SetSysClockTo72();

	ADC_DMA_init();
	I2C1_Slave_init();

    while(1)
    {

    }
}

Сначала мы устанавливаем максимальную частоту работы контроллера. Максимальная скорость необходима, когда нужно избежать любых задержек на шине I2C. Затем запускаем работу ADC с использованием DMA. О ADC читайте здесь. О DMA читайте здесь. И, наконец, выполняем инициализацию шины I2C как Slave. Как видите, ничего сложного.

Теперь подключим наш модуль STM32 к Raspberry Pi. К каналам ADC подключим потенциометры. И будем считывать с нашего контроллера показатели ADC. Не забываем, что для работы шины I2C нужно на каждую линию шины установить подтягивающие резисторы.

iic_slave_circuit

В консоли Raspberry проверим видно ли наше устройство на шине I2C (о том, как использовать шину I2C на Raspberry читайте здесь):

i2cdetect -y 1

stm32_iic_slave_01

Как видите, адрес устройства 0x27, хотя мы указали 0x4E. Когда будет время, подумайте – почему так произошло.

Для считывания из регистров I2C-Slave устройства выполняем команду:

i2cget -y 1 0x27 0x00

Где:
0x27 – адрес устройства,
0x00 – адрес регистра (0x00…0xFF).

stm32_iic_slave_02

Для записи в регистры I2C-Slave устройства выполняем команду:

i2cset -y 1 0x27 0xA0 0xDD

Де:
0x27 – адрес устройства,
0xA0 – адрес регистра
0xDD -8-bit данные (0x00…0xFF)

Предыдущая команда записала число 0xDD в регистр 0xA0 (писать в первые 16 регистров можно, и смысла нет, по они отведены под ADC). Теперь прочитаем:

i2cget -y 1 0x27 0xA0

stm32_iic_slave_03

Чтобы упростить процесс считывания данных ADC-каналов я написал скрипт:

#!/usr/bin/env python
import smbus
import time

bus = smbus.SMBus(1)
address = 0x27

while (1):
	ADC = {};
	for i in range(0, 8):
		LBS = bus.read_byte_data(address, 0x00+i*2)
		MBS = bus.read_byte_data(address, 0x00+i*2+1)
		ADC[i] = MBS*256 + LBS

	print ADC
	time.sleep(0.2)

Он опрашивает и выводит в консоль результаты всех 8-ми ADC-каналов.

stm32_iic_slave_04

Аналогичным образом можно объединить несколько микроконтроллеров. Один из них должен быть Master (смотри предыдущую статью), другие Slave.

Желаю успехов!

Смотри также:

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

 
Translate
Архіви

© 2011-2017 Андрій Корягін, Кременчук, Україна