20. STM32. Програмування STM32F103. I2C Slave
У попередній статті ми розглянули роботу STM32 з шиною I2C у якості Майстра. Тобто, він був ведучий і опитував сенсор. Тепер зробимо так, щоб STM32 був Slave-ом і відповідав на запити, тобто сам працював як сенсор. Ми виділимо 255 байт пам`яті під регістри з адресами від 0 до 0xFF, і дозволимо Майстру в них писати/читати. А щоб приклад був не таким примітивним, зробимо з нашого STM32, ще і аналого-цифровий перетворювач з інтерфейсом I2C. ADC буде обробляти 8 каналів. Результати перетворень контролер буде віддавати Майстру при читанні з регістрів. Оскільки результат перетворення ADC займає 12 біт, нам потрібно буде 2 регістра (2 байта) на кожний канал ADC.
Весь функціонал який стосується I2C знаходиться у файлах 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 потрібно на кожну лінію шини встановити підтягуючі резистори.
У консолі Raspberry перевіримо чи взагалі видно наш пристрій на шині I2C (про те, як використовувати шину I2C на Raspberry читайте тут):
i2cdetect -y 1
Як бачите, адреса пристрою 0x27, хоча ми вказали 0x4E. Як матимете час, подумайте - чому так сталося.
Для зчитування з регістрів I2C-Slave приладу виконуємо команду:
i2cget -y 1 0x27 0x00
Де: 0x27 - адреса пристрою, 0x00 - адреса регістру (0x00...0xFF).
Для запису у регістри I2C-Slave приладу виконуємо команду:
i2cset -y 1 0x27 0xA0 0xDD
Де: 0x27 - адреса пристрою, 0xA0 - адреса регістру 0xDD -8-bit дані (0x00...0xFF)
Попередня команда записала число 0xDD у регістр 0xA0 (писати у перші 16 регістрів можна, та сенсу немає, по вони відведені під ADC). Тепер прочитаємо:
i2cget -y 1 0x27 0xA0
Щоб спростити процес зчитування даних 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-каналів.
Аналогічним чином можна об`єднати декілька мікроконтролерів. Один з них має бути Master (дивись попередню статтю), інші Slave.
Бажаю успіхів!
Дивись також:
- 1. STM32. Програмування STM32F103. Тестова плата. Прошивка через UART та через ST-Link
- 2. STM32. Програмування. IDE для STM32
- 3. STM32. Програмування STM32F103. GPIO
- 4. STM32. Програмування STM32F103. Тактування
- 5. STM32. Програмування STM32F103. USART
- 6. STM32. Програмування STM32F103. NVIC
- 7. STM32. Програмування STM32F103. ADC
- 8. STM32. Програмування STM32F103. DMA
- 9. STM32. Програмування STM32F103. TIMER
- 10. STM32. Програмування STM32F103. TIMER. Захоплення сигналу
- 11. STM32. Програмування STM32F103. TIMER. Encoder
- 12. STM32. Програмування STM32F103. TIMER. PWM
- 13. STM32. Програмування STM32F103. EXTI
- 14. STM32. Програмування STM32F103. RTC
- 15. STM32. Програмування STM32F103. BKP
- 16. STM32. Програмування STM32F103. Flash
- 17. STM32. Програмування STM32F103. Watchdog
- 18. STM32. Програмування STM32F103. Remap
- 19. STM32. Програмування STM32F103. I2C Master
- 20. STM32. Програмування STM32F103. I2C Slave
- 21. STM32. Програмування STM32F103. USB
- 22. STM32. Програмування STM32F103. PWR
- 23. STM32. Програмування STM32F103. Option bytes
- 24. STM32. Програмування STM32F103. Bootloader
- STM32. Скачати приклади
- System Workbench for STM32 Інсталяція на Ubuntu
- Keil uVision5 – IDE для STM32
- IAR Workbench – IDE для STM32
- Керування безколекторним двигуном постійного струму (BLDC) за допомогою STM32
- Керування PMSM за допомогою STM32
Tags
web java-script bmp280 adc bldc stm32 rs-232 programmator 3d-printer flash pwm sms motor docker raspberry-pi meteo gps ngnix bme280 timer ssd1331 mpu-6050 bkp battery rfid st-link tim mpx4115a ssd1306 encoder atmega pmsm wifi options rtc examples nvic soldering mongodb esp8266 books lcd foc flask barometer bluetooth ethernet brushless uart watchdog servo gpio solar git remap dma usart eb-500 smd nodemcu sensors displays html python capture dht11 led i2c eeprom piezo exti websocket max1674 usb dc-dc avr hih-4000 css mpu-9250
Архіви




