Nie wiem czy ktoś będzie potrzebował, ale wrzucam, na wypadek, gdyby mi było jeszcze kiedyś potrzebne.
Kod: Zaznacz cały
/* Includes */
#include <stddef.h>
#include "stm32f10x.h"
#define I2C_SLAVE_ADDR 0x06 //adres urządzenia slave
#define I2C_REG_ADDR 0x31 //rejestr do zapisu
#define I2C_DATA 199 //Dana I2C - w tym przypadku rozdzielczość enkodera
static uint8_t fac_us = 0;
void delay_init( uint8_t SYSCLK )
{
SysTick->CTRL &= 0xFFFFFFFB;
fac_us = SYSCLK / 8;
}
void delay_ms( uint16_t ms )
{
while( ms-- )
delay_us( 999 );
}
void delay_us( uint32_t us )
{
uint32_t temp;
SysTick->LOAD = us * fac_us;
SysTick->VAL = 0x00;
SysTick->CTRL = 0x01;
do
{
temp = SysTick->CTRL;
}
while( temp & 0x01 &&!( temp & ( 1 << 16 )));
SysTick->CTRL = 0x00;
SysTick->VAL = 0x00;
}
volatile void delay_ticks(volatile uint32_t t)
{
while( (volatile)t--);
}
void led_init()
{
RCC->APB2ENR|= RCC_APB2ENR_IOPCEN;
GPIOB->CRH &=~ (GPIO_CRH_MODE13 | GPIO_CRH_CNF13);
GPIOC->CRH |= GPIO_CRH_MODE13_0;//Output mode, max speed 10 MHz
}
void led_OFF()
{
GPIOC->BSRR = GPIO_BSRR_BS13;
}
void led_ON()
{
GPIOC->BSRR = GPIO_BSRR_BR13;
}
void led_TGL()
{
GPIOC->ODR ^= GPIO_ODR_ODR13;
}
void I2C_init(void)
{
// Włącz taktowanie dla I2C
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
// Konfiguruj piny jako alternatywne funkcje open-drain
GPIOB->CRL &= ~(GPIO_CRL_MODE6 | GPIO_CRL_CNF6 | GPIO_CRL_MODE7 | GPIO_CRL_CNF7);
GPIOB->CRL |= GPIO_CRL_CNF6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE6 | GPIO_CRL_MODE7;
delay_ms(500);
// Konfiguruj parametry I2C1
I2C1->CR1 &= ~I2C_CR1_PE; // Wyłącz I2C1 przed konfiguracją
I2C1->CR1 |= I2C_CR1_SWRST; // Zresetuj I2C1
delay_ms(1);
I2C1->CR1 &= ~I2C_CR1_SWRST;
// Skonfiguruj prędkość I2C1
I2C1->CR2 &= ~I2C_CR2_FREQ;
I2C1->CR2 |= 1; // Ustaw czestotliwość APB1 na 36 MHz (odpowiednie dla większości konfiguracji mikrokontrolera)
// Wyłącz przerwania I2C
I2C1->CR2 &= ~I2C_CR2_ITEVTEN;
I2C1->CCR &= ~I2C_CCR_CCR;
I2C1->CCR |= 180; // Ustaw CCR na wartość zapewniającą prędkość 100 kHz
I2C1->TRISE = 37; // Ustaw TRISE na wartość zapewniającą odpowiednie opóźnienie dla prędkości 100 kHz
// Włącz I2C1
I2C1->CR1 |= I2C_CR1_PE;
}
void I2C_SendByte(uint8_t slave_addr, uint8_t reg_addr, uint8_t data)
{
// Czekaj, aż I2C1 będzie gotowy do transmisji
while ((I2C1->SR2 & I2C_SR2_BUSY) != 0);
// Generuj warunek START
I2C1->CR1 |= I2C_CR1_START;
// Czekaj na zakończenie warunku START
while ((I2C1->SR1 & I2C_SR1_SB) == 0);
// Wysłanie adresu slave (zapis)
I2C1->DR = (slave_addr << 1) & 0xFE;
while (!(I2C1->SR1 & I2C_SR1_ADDR)); // Czekaj na potwierdzenie adresu
// Odczytanie SR2
(void)I2C1->SR2;
// Wysłanie adresu rejestru
I2C1->DR = reg_addr;
while (!(I2C1->SR1 & I2C_SR1_TXE)); // Czekaj na pusty bufor
// Wysłanie danych
I2C1->DR = data;
while (!(I2C1->SR1 & I2C_SR1_TXE)); // Czekaj na pusty bufor
// Wysłanie stopu
I2C1->CR1 |= I2C_CR1_STOP;
}
uint8_t I2C_ReadByte(uint8_t slave_addr, uint8_t reg_addr)
{
uint8_t receivedData;
// Czekaj, aż I2C1 będzie gotowy do transmisji
while ((I2C1->SR2 & I2C_SR2_BUSY) != 0);
// Generuj warunek START
I2C1->CR1 |= I2C_CR1_START;
// Czekaj na zakończenie warunku START
while ((I2C1->SR1 & I2C_SR1_SB) == 0);
// Wysłanie adresu slave (zapis)
I2C1->DR = (slave_addr << 1) & 0xFE;
while (!(I2C1->SR1 & I2C_SR1_ADDR)); // Czekaj na potwierdzenie adresu
// Odczytanie SR2
(void)I2C1->SR2;
// Wysłanie adresu rejestru
I2C1->DR = reg_addr;
while (!(I2C1->SR1 & I2C_SR1_TXE));
// Czekaj na pusty bufor
// Generuj warunek RESTART
I2C1->CR1 |= I2C_CR1_START;
// Czekaj na zakończenie warunku RESTART
while ((I2C1->SR1 & I2C_SR1_SB) == 0);
// Wysłanie adresu slave (odczyt)
I2C1->DR = (slave_addr << 1) | 0x01; // Ustaw bit kierunku na odczyt
while (!(I2C1->SR1 & I2C_SR1_ADDR)); // Czekaj na potwierdzenie adresu
// Odczytanie SR2
(void)I2C1->SR2;
// Wyłącz przerwania I2C
I2C1->CR2 &= ~I2C_CR2_ITEVTEN;
// Włącz odczyt ACK
I2C1->CR1 &= ~I2C_CR1_ACK;
// Generuj warunek STOP
I2C1->CR1 |= I2C_CR1_STOP;
// Czekaj na odczyt bajtu danych
while (!(I2C1->SR1 & I2C_SR1_RXNE));
// Odczytaj otrzymany bajt danych
receivedData = I2C1->DR;
return receivedData;
}
int main(void)
{
delay_init(72);
led_init();
led_ON();
delay_ms(200);
led_OFF();
I2C_init();
delay_ms(50);
// Wysłanie danych
I2C_SendByte(I2C_SLAVE_ADDR, I2C_REG_ADDR, I2C_DATA);//Programowanie rejestru
I2C_SendByte(I2C_SLAVE_ADDR, 0x09, 0xb3);//Klucz programowania
I2C_SendByte(I2C_SLAVE_ADDR, 0x0A, 0x05);//Komenda programowania
delay_ms(700);//Odczekanie conajmniej 600 ms na zakończenie operacji
uint8_t read = I2C_ReadByte(I2C_SLAVE_ADDR, I2C_REG_ADDR);//odczyt zapisanego rejestru
if(read != I2C_DATA)//porównanie
{
while(1)//jeśli nieprawidłowe, to LED mróga
{
led_TGL();
delay_ms(200);
}
}
led_ON();//Led świeci, prawidłowy odczyt
while (1);
}

Konfiguracja pod płytkę bluepill.
SCL to noga PB6 mikrokontrolera, SDA to noga PB7.
Po poprawnym ustawieniu rejestru, dioda na wyjściu PC13 zaświeci, gdy odczytana wartość nie zgodzi się z zapisaną, dioda będzie mrugać.
Szkoda się bawić w enkodery na transoptorach bo jakość sygnału kwadraturowego z wykonanego enkodera będzie zawsze powodować ograniczenie maksymalnej prędkości.
Ten enkoder kosztuje grosze i naprawdę uważam, że wart jest uwagi.