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
bme280 bmp280 gps mpu-6050 options stm32 ssd1331 ssd1306 eb-500 3d-printer soldering tim mpu-9250 dma watchdog piezo exti web raspberry-pi docker ngnix solar bluetooth foc html css brushless flask dc-dc capture gpio avr rs-232 mpx4115a atmega mongodb st-link barometer pwm nvic git java-script programmator dht11 hih-4000 pmsm encoder max1674 smd sensors rtc adc lcd motor timer meteo examples i2c usb flash sms rfid python esp8266 servo books bldc remap eeprom bkp battery ethernet uart usart displays led websocket nodemcu wifi
Архіви




