#include "stm32f103xb.h"
void I2C_PWR();
void I2C_read();
void Delay();
void PWM_Init();
volatile uint8_t Address_Read;
int16_t data_x,data_y,data_z;
#define delay_time 10
void init() {
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN|RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;
RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;
GPIOB->CRH = 0x4444FF44; // AF open drain
GPIOB->CRL = 0x4444444B; // PB0 alt for pwm
GPIOA->CRL = 0x44444333; // LED PA0 output G.P. push-pull, PA1 & PA2 outputs for motor
I2C2->CR1 &= ~ I2C_CR1_PE;
I2C2->CR1 |= (1 << 15); // reset the I2C
I2C2->CR1 &= ~(1 << 15); // Normal operation
I2C2->CR2 |= 8; // I2C APB clock frequency
I2C2->CCR = 40; // I2C Standard Mode
I2C2->TRISE = 9;
I2C2->CR1 |= I2C_CR1_PE;
}
void motorControl(int16_t gyroData) {
// PA1 and PA2 are used for motor direction control
if (gyroData > 0) {
// Rotate clockwise
GPIOA->ODR &= ~GPIO_ODR_ODR2; // PA2 = 0
GPIOA->ODR |= GPIO_ODR_ODR1; // PA1 = 1
} else if (gyroData < 0) {
// Rotate counter-clockwise
GPIOA->ODR |= GPIO_ODR_ODR2; // PA2 = 1
GPIOA->ODR &= ~GPIO_ODR_ODR1; // PA1 = 0
gyroData = gyroData * -1;
}
TIM3->CCR3= gyroData;
}
int main(){
init();
PWM_Init();
I2C_PWR();
while(1){
I2C_read();
motorControl(data_x);
if(data_x>0){
GPIOA->ODR|=(1<<0);
}
else{
GPIOA->ODR&=~(1<<0);
}
}
}
void PWM_Init() {
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->CCER |= (1 << 8);
TIM3->CCMR2 |= 0b1101000;
TIM3->CR1 =0b1000001;
TIM3->PSC = 0; // Set the prescaler value
TIM3->ARR = 4000; // Set the auto-reload value
TIM3->EGR=1;
TIM3->CR1 |= 0x01; // start counting
}
void I2C_PWR(){
while(I2C2->SR2 & I2C_SR2_BUSY); // check if the I2C is busy
I2C2->CR1|=I2C_CR1_START; // send start bit
while(!(I2C2->CR1 & I2C_SR1_SB)); // check start bit
Delay(); // small delay inserted after the start bit for timing
I2C2->DR = 0x68 << 1 ; // send address
while (!(I2C2->SR1 & I2C_SR1_ADDR));// check for address, skip in debugging
Address_Read = I2C2->SR1 | I2C2->SR2;// read SR1 and SR2 to clear the ADDR bit
while(!(I2C2->SR1 & (I2C_SR1_TXE))); // I2C ready for next byte
I2C2->DR=0x6B; // send address of pwr register
while(!(I2C2->SR1 & (I2C_SR1_TXE))); // I2C ready for next byte
I2C2->DR=0; // send 0
while(!(I2C2->SR1 & (I2C_SR1_BTF))); // check last byte transmission ended
I2C2->CR1|=I2C_CR1_STOP; // Stop I2C
}
void I2C_read(){
while(I2C2->SR2 & I2C_SR2_BUSY);
I2C2->CR1|=I2C_CR1_START; // send start bit
while(!(I2C2->CR1 & I2C_SR1_SB)); // check start bit
Delay(); // small delay inserted after the start bit for timing
I2C2->DR = (0x68 << 1) ; // send address
while (!(I2C2->SR1 & I2C_SR1_ADDR));// check for address, skip in debugging
Address_Read = I2C2->SR1 | I2C2->SR2;// read SR1 and SR2 to clear the ADDR bit
while(!(I2C2->SR1 & (I2C_SR1_TXE))); // I2C ready for next byte
I2C2->DR=59; // send address of a_x register
while(!(I2C2->SR1 & (I2C_SR1_BTF))); // check last byte transmission ended
I2C2->CR1|=I2C_CR1_START|I2C_CR1_ACK; // double start, enable acknowledgment
while(!(I2C2->CR1 & I2C_SR1_SB)); // check start bit
Delay(); // small delay inserted after the start bit for timing
I2C2->DR = (0x68 << 1)|1 ; // send address
while(!(I2C2->SR1 & (I2C_SR1_ADDR)));// check for address, skip in debugging}
Address_Read = I2C2->SR1 | I2C2->SR2;// read SR1 and SR2 to clear the ADDR bit
while(!(I2C2->SR1 & I2C_SR1_RXNE));// check for data received, skip in debugging
data_x= I2C2->DR;
while(!(I2C2->SR1 & I2C_SR1_RXNE));// check for data received, skip in debugging
data_x= (data_x<<8)|I2C2->DR;
while(!(I2C2->SR1 & I2C_SR1_RXNE));// check for data received, skip in debugging
data_y= I2C2->DR;
while(!(I2C2->SR1 & I2C_SR1_RXNE));// check for data received, skip in debugging
data_y= (data_y<<8)|I2C2->DR;
while(!(I2C2->SR1 & I2C_SR1_RXNE));// check for data received, skip in debugging
data_z= I2C2->DR;
I2C2->CR1 |= (1 << 9); // Stop I2C before the end of the last byte
I2C2->CR1 &= ~I2C_CR1_ACK; // Stop ACK
while(!(I2C2->SR1 & I2C_SR1_RXNE));// check for data received, skip in debugging
data_z= (data_z<<8)|I2C2->DR;
}
void Delay(){
for( int i=0;i<=delay_time;i++);
}