I2C (Устаревшая статья): различия между версиями
Материал из MIK32 микроконтроллер
Sh-sergey (обсуждение | вклад) (Полностью удалено содержимое страницы) Метки: очистка правка через визуальный редактор |
Андрей (обсуждение | вклад) Нет описания правки |
||
Строка 1: | Строка 1: | ||
Пример использования I2C MIK32 в режиме мастер<syntaxhighlight lang="c++" line="1"> | |||
#include "common.h" | |||
#include "i2c_loop_common.h" | |||
#include "stdbool.h" | |||
void i2c_init(I2C_TypeDef* i2c) | |||
{ | |||
//Включаем тактирование необходимых блоков - GPIO_0, GPIO_1, GPIO_2 и модуля выбора режима GPIO | |||
PM->CLK_APB_P_SET |= PM_CLOCK_GPIO_0_M | PM_CLOCK_I2C_0_M; | |||
PM->CLK_APB_M_SET |= PM_CLOCK_PAD_CONFIG_M | PM_CLOCK_WU_M | PM_CLOCK_PM_M ; | |||
// обнуление регистра управления | |||
i2c->CR1 = 0; | |||
/* | |||
* Инициализация i2c | |||
* TIMING - регистр таймингов | |||
* | |||
* SCLDEL - Задержка между изменением SDA и фронтом SCL в режиме ведущего и ведомого при NOSTRETCH = 0 | |||
* | |||
* SDADEL - Задержка между спадом SCL и изменением SDA в режиме ведущего и ведомого при NOSTRETCH = 0 | |||
* | |||
* SCLL - Время удержания SCL в состоянии логического «0» в режиме веедущего | |||
* | |||
* SCLH - Время удержания SCL в состоянии логической «1» в режиме веедущего | |||
* | |||
* PRESC - Делитель частоты I2CCLK. Используется для вычесления периода сигнала TPRESC для счетчиков предустановки, | |||
* удержания, уровня «0»и «1» | |||
* | |||
*/ | |||
i2c->TIMINGR = I2C_TIMINGR_SCLDEL(1) | I2C_TIMINGR_SDADEL(1) | | |||
I2C_TIMINGR_SCLL(20) | I2C_TIMINGR_SCLH(20) | I2C_TIMINGR_PRESC(3); //частота 164,7 кГц tsync1 + tsync2 = 10^(-6) | |||
/* | |||
* | |||
* CR1 - Регистр управления | |||
* | |||
* PE - Управление интерфейсом: 0 – интерфейс выключен; 1 – интерфейс включен | |||
* | |||
* STOPIE - Разрешение прерывания детектировании STOP: 0 – прерывание запрещено; 1 – прерывание разрешено | |||
* | |||
*/ | |||
i2c->CR1 = I2C_CR1_PE_M; | |||
} | |||
void i2c_master_write(I2C_TypeDef* i2c, uint8_t slave_adr, uint8_t data[], uint8_t byte_count, bool shift) | |||
{ | |||
// shift - true когда адрес ведомого должен быть сдвинут на 1 бит | |||
if(!shift) | |||
{ | |||
slave_adr = slave_adr << 1; | |||
} | |||
xprintf("Отправка по адресу 0x%02x байта %d\n", slave_adr, data[0]); | |||
/* | |||
* | |||
* CR2 - регистр управления 2 | |||
* | |||
* SADD - адрес ведомого | |||
* | |||
* RD_WRN - Направление передачи: 0 – ведущий в режиме записи; 1 – ведущий в режиме чтения | |||
* | |||
* AUTOEND - Управление режимом автоматического окончания: 0 – автоматическое окончание выкл; 1 – автоматическе окончание вкл | |||
* | |||
*/ | |||
i2c->CR2 = I2C_CR2_SADD(slave_adr) | I2C_CR2_WR_M | I2C_CR2_NBYTES(byte_count) | I2C_CR2_AUTOEND_M; // sizeof(data) | |||
i2c->TXDR = data[0]; // первая загрузка в буфер | |||
while(i2c->ISR & I2C_ISR_TXE_M); // TXE = 0 - регистр TXDR заполнен | |||
i2c->CR2 |= I2C_CR2_START_M; // старт отправки адреса, а затем данных | |||
for (uint8_t i = 1; i < byte_count; i++) | |||
{ | |||
xprintf("Отправка по адресу 0x%02x байта %d\n", slave_adr, data[i]); | |||
i2c->TXDR = data[i]; | |||
while(i2c->ISR & I2C_ISR_TXE_M); // TXE = 0 - регистр TXDR заполнен | |||
} | |||
//while (!(i2c->ISR & I2C_ISR_TC_M)); // TC = 1 - все байты переданы | |||
//while(!(i2c->ISR & I2C_ISR_TXIS_M)); // TXIS - уставляется после оправки каждого байта и полученя ACK | |||
//while(!(i2c->ISR & I2C_ISR_NACKF_M )); // NACKF - уставляется после полученя NACK | |||
//i2c->CR2 |= I2C_CR2_STOP_M; // отправка бита stop вручную | |||
} | |||
void i2c_master_read(I2C_TypeDef* i2c, uint8_t slave_adr, uint8_t data[], uint8_t byte_count, bool shift) | |||
{ | |||
// shift - true когда адрес ведомого должен быть сдвинут на 1 бит | |||
if(!shift) | |||
{ | |||
slave_adr = slave_adr << 1; | |||
} | |||
xprintf("\nI2C reads bytes back\n"); | |||
i2c->CR2 = I2C_CR2_SADD(slave_adr) | I2C_CR2_RD_M | I2C_CR2_NBYTES(byte_count) | I2C_CR2_AUTOEND_M; // I2C_CR2_NBYTES(sizeof(data)/sizeof(data[0])) | |||
i2c->CR2 |= I2C_CR2_START_M; | |||
for(uint8_t i = 0; i < byte_count; i++) | |||
{ | |||
while(!(i2c->ISR & I2C_ISR_RXNE_M)); // байт принят когда RXNE = 1 | |||
data[i] = i2c->RXDR; // чтение байта и сброс RXNE | |||
} | |||
} | |||
int main() | |||
{ | |||
uint8_t slave_adr = 0x36; // адрес ведомого | |||
uint16_t to_send = 4000; // данные для оптавки | |||
uint8_t data[2] = {to_send >> 8, to_send & 0b0000000011111111}; // массив байтов на отправку | |||
i2c_init(I2C_0); // инициализация блока i2c | |||
i2c_master_write(I2C_0, slave_adr, data, 2, false); // запись данных по адресу slave_adr = 0x36 без сдвига адреса | |||
i2c_master_read(I2C_0, slave_adr, data, 2, false); // чтение данных по адресу slave_adr = 0x36 без сдвига адреса | |||
while (1) | |||
{ | |||
} | |||
} | |||
</syntaxhighlight> |
Версия от 21:57, 2 мая 2022
Пример использования I2C MIK32 в режиме мастер
#include "common.h" #include "i2c_loop_common.h" #include "stdbool.h" void i2c_init(I2C_TypeDef* i2c) { //Включаем тактирование необходимых блоков - GPIO_0, GPIO_1, GPIO_2 и модуля выбора режима GPIO PM->CLK_APB_P_SET |= PM_CLOCK_GPIO_0_M | PM_CLOCK_I2C_0_M; PM->CLK_APB_M_SET |= PM_CLOCK_PAD_CONFIG_M | PM_CLOCK_WU_M | PM_CLOCK_PM_M ; // обнуление регистра управления i2c->CR1 = 0; /* * Инициализация i2c * TIMING - регистр таймингов * * SCLDEL - Задержка между изменением SDA и фронтом SCL в режиме ведущего и ведомого при NOSTRETCH = 0 * * SDADEL - Задержка между спадом SCL и изменением SDA в режиме ведущего и ведомого при NOSTRETCH = 0 * * SCLL - Время удержания SCL в состоянии логического «0» в режиме веедущего * * SCLH - Время удержания SCL в состоянии логической «1» в режиме веедущего * * PRESC - Делитель частоты I2CCLK. Используется для вычесления периода сигнала TPRESC для счетчиков предустановки, * удержания, уровня «0»и «1» * */ i2c->TIMINGR = I2C_TIMINGR_SCLDEL(1) | I2C_TIMINGR_SDADEL(1) | I2C_TIMINGR_SCLL(20) | I2C_TIMINGR_SCLH(20) | I2C_TIMINGR_PRESC(3); //частота 164,7 кГц tsync1 + tsync2 = 10^(-6) /* * * CR1 - Регистр управления * * PE - Управление интерфейсом: 0 – интерфейс выключен; 1 – интерфейс включен * * STOPIE - Разрешение прерывания детектировании STOP: 0 – прерывание запрещено; 1 – прерывание разрешено * */ i2c->CR1 = I2C_CR1_PE_M; } void i2c_master_write(I2C_TypeDef* i2c, uint8_t slave_adr, uint8_t data[], uint8_t byte_count, bool shift) { // shift - true когда адрес ведомого должен быть сдвинут на 1 бит if(!shift) { slave_adr = slave_adr << 1; } xprintf("Отправка по адресу 0x%02x байта %d\n", slave_adr, data[0]); /* * * CR2 - регистр управления 2 * * SADD - адрес ведомого * * RD_WRN - Направление передачи: 0 – ведущий в режиме записи; 1 – ведущий в режиме чтения * * AUTOEND - Управление режимом автоматического окончания: 0 – автоматическое окончание выкл; 1 – автоматическе окончание вкл * */ i2c->CR2 = I2C_CR2_SADD(slave_adr) | I2C_CR2_WR_M | I2C_CR2_NBYTES(byte_count) | I2C_CR2_AUTOEND_M; // sizeof(data) i2c->TXDR = data[0]; // первая загрузка в буфер while(i2c->ISR & I2C_ISR_TXE_M); // TXE = 0 - регистр TXDR заполнен i2c->CR2 |= I2C_CR2_START_M; // старт отправки адреса, а затем данных for (uint8_t i = 1; i < byte_count; i++) { xprintf("Отправка по адресу 0x%02x байта %d\n", slave_adr, data[i]); i2c->TXDR = data[i]; while(i2c->ISR & I2C_ISR_TXE_M); // TXE = 0 - регистр TXDR заполнен } //while (!(i2c->ISR & I2C_ISR_TC_M)); // TC = 1 - все байты переданы //while(!(i2c->ISR & I2C_ISR_TXIS_M)); // TXIS - уставляется после оправки каждого байта и полученя ACK //while(!(i2c->ISR & I2C_ISR_NACKF_M )); // NACKF - уставляется после полученя NACK //i2c->CR2 |= I2C_CR2_STOP_M; // отправка бита stop вручную } void i2c_master_read(I2C_TypeDef* i2c, uint8_t slave_adr, uint8_t data[], uint8_t byte_count, bool shift) { // shift - true когда адрес ведомого должен быть сдвинут на 1 бит if(!shift) { slave_adr = slave_adr << 1; } xprintf("\nI2C reads bytes back\n"); i2c->CR2 = I2C_CR2_SADD(slave_adr) | I2C_CR2_RD_M | I2C_CR2_NBYTES(byte_count) | I2C_CR2_AUTOEND_M; // I2C_CR2_NBYTES(sizeof(data)/sizeof(data[0])) i2c->CR2 |= I2C_CR2_START_M; for(uint8_t i = 0; i < byte_count; i++) { while(!(i2c->ISR & I2C_ISR_RXNE_M)); // байт принят когда RXNE = 1 data[i] = i2c->RXDR; // чтение байта и сброс RXNE } } int main() { uint8_t slave_adr = 0x36; // адрес ведомого uint16_t to_send = 4000; // данные для оптавки uint8_t data[2] = {to_send >> 8, to_send & 0b0000000011111111}; // массив байтов на отправку i2c_init(I2C_0); // инициализация блока i2c i2c_master_write(I2C_0, slave_adr, data, 2, false); // запись данных по адресу slave_adr = 0x36 без сдвига адреса i2c_master_read(I2C_0, slave_adr, data, 2, false); // чтение данных по адресу slave_adr = 0x36 без сдвига адреса while (1) { } }