stm32实例学习
以stm32f103rc为例
-
系统的启动—配置系统时钟,启动运行
startup_stm32f0x_hd.s:栈空间的设置,进入Rest_Handler函数,设置异常向量表,时钟初始化,跳转到__main执行系统的一些准备工作,跳转到main函数;初始化时钟后,单片机就能开始工作
void system_init(void)
{
RCC->CR |= 1 << 16; //HSE ON
while(!(RCC->CR & (1 << 17))); //Wait HSE ready
RCC->CFGR &= ~(0xF << 4); //AHB
RCC->CFGR |= 4 << 8; //APB1 div 2
RCC->CFGR &= ~(7 << 11); //APB2
RCC->CFGR |= 7 << 18; //PLL
RCC->CFGR &= ~(1 << 17);
RCC->CFGR |= 1 << 16; //HSE as PLL input
RCC->CR |= 1 << 24; //PLL ON
while(!(RCC->CR & (1 << 25)));
FLASH->ACR |= 2 << 0; //latency
RCC->CFGR |= 2 << 0;
while(((RCC->CFGR >> 2) & 0x3) != 0x02);
}
- led
void led_init(void)
{
RCC->APB2ENR = 1 << 2; //GPIOA clock
GPIOA->CRH &= ~(0xF << 0);
GPIOA->CRH |= 3 << 0;
GPIOA->BSRR |= 1 << 8;
RCC->APB2ENR = 1 << 5; //GPIOD clock
GPIOD->CRL &= ~(0xF << 8);
GPIOD->CRL |= 3 << 8;
GPIOD->BSRR |= 1 << 2;
}
- 单片机进入待机状态并唤醒
void pwr_init(void)
{
RCC->APB1ENR |= 1 << 28; //power clock
PWR->CSR |= 1 << 8; //WKUP pin enable
}
/*
set SLEEPDEEP
set PDDS
clear WUF
WFI
*/
void pwr_go_to_standby(void)
{
SCB->SCR |= 1 << 2;
PWR->CR |= 1 << 1;
PWR->CR |= 1 << 2;
__WFI();
}
监测单片机的电压PVD
```c
void pwr_init(void)
{
RCC->APB1ENR |= 1 << 28; //power clock
RCC->APB2ENR |= 1 << 0;
PWR->CR |= 7 << 5; //2.9V
PWR->CR |= 1 << 4; //enable PVD
EXTI->IMR |= 1 << 16; //interrupt
EXTI->FTSR |= 1 << 16;
EXTI->RTSR |= 1 << 16;
nvic_init(PVD_IRQn, 2, 2, 2);
}
void PVD_IRQHandler(void)
{
if(EXTI->PR & (1 << 16))
{
EXTI->PR |= 1 << 16;
GPIOD->ODR ^= 1 << 2;
}
}
4. 延时
```c
static uint32_t usPerTicks = 9;
static volatile uint32_t system_mills = 0;
static volatile uint32_t systick_pending = 0;
static volatile uint32_t systick_stamps = 0;
void delay_init(void)
{
SysTick->CTRL |= 1 << 1; //en interrupt
SysTick->CTRL &= ~(1 << 2); //clock = system clock / 8;
SysTick->LOAD = usPerTicks * 1000; //ticks per ms
SysTick->VAL= 0;
SysTick->CTRL |= 1 << 0; //start
}
void SysTick_Handler(void)
{
system_mills++;
systick_stamps = SysTick->VAL;
systick_pending = 0;
}
uint32_t micros_isr(void)
{
register uint32_t ticks, ms, pending;
ticks = SysTick->VAL;
if(SCB->ICSR & 0x1FF)
{
systick_pending = 1;
ticks = SysTick->VAL;
}
pending = systick_pending;
ms = system_mills;
return ((ms + pending) * 1000 + (usPerTicks * 1000 - ticks) / usPerTicks);
}
uint32_t micros(void)
{
register uint32_t ticks, ms;
if(SysTick->CTRL & (1 << 16))
{
return micros_isr();
}
do
{
ms = system_mills;
ticks = SysTick->VAL;
}while((ms != system_mills) || (ticks > systick_stamps));
return (ms * 1000 + (usPerTicks * 1000 - ticks) / usPerTicks);
}
void delay_us(uint32_t nus)
{
uint32_t now = micros();
while(micros() - now < nus);
}
void delay_ms(uint32_t nms)
{
while(nms--)
{
delay_us(1000);
}
}
- 看门狗
独立看门狗
void iwdg_init(void)
{
RCC->CSR |= 1 << 0;
while(!(RCC->CSR & (1 << 1)));
IWDG->KR = 0x5555; //cancel protetion
IWDG->PR = 4; //prescaler
IWDG->RLR = 625; //load val
IWDG->KR = 0xCCCC; //start
IWDG->KR = 0xAAAA; //reload
}
void iwdg_feed(void)
{
IWDG->KR = 0xAAAA;
}
窗口看门狗
void wwdg_init(void)
{
RCC->APB1ENR |= 1 << 11; //WWDG clock
WWDG->CFR |= 1 << 9; //interrupt
WWDG->CFR |= 80; //config window
WWDG->CFR |= 3 << 7;
WWDG->CR = 0x7F;
WWDG->CR |= 1 << 7; //start
nvic_init(WWDG_IRQn, 2, 3, 2);
}
void wwdg_feed(void)
{
WWDG->CR = 0x7F;
}
void WWDG_IRQHandler(void)
{
WWDG->SR = 0;
wwdg_feed();
GPIOD->ODR ^= 1 << 2;
}
- 备份寄存器
void backup_init(void)
{
RCC->APB1ENR |= 1 << 28; //PWR
RCC->APB1ENR |= 1 << 27; //BKP clock
PWR->CR |= 1 << 8; //cancel backup protection
if(RCC->CSR & (1 << 27)) //power down/up
{
if(BKP->DR1 != 0x55AA)
{
BKP->DR1 = 0x55AA;
}
else
{
GPIOD->ODR &= ~(1 << 2);
}
}
}
- 中断
void exti_init(void)
{
RCC->APB2ENR |= 1 << 2; //GPIOA
RCC->APB2ENR |= 1 << 0; //AFIO
GPIOA->CRL &= ~(0xF << 0); //input
GPIOA->CRL |= 2 << 0;
GPIOA->ODR &= ~(1 << 0);
AFIO->EXTICR[0] &= ~(0xF << 0); //gpio--exti connect
EXTI->IMR |= 1 << 0; //exti
EXTI->RTSR |= 1 << 0;
nvic_init(EXTI0_IRQn, 2, 1, 2);
}
void EXTI0_IRQHandler(void)
{
if(EXTI->PR & (1 << 0))
{
EXTI->PR |= 1 << 0;
GPIOD->ODR ^= 1 << 2;
}
}
- 串口的基本使用
void usart_init(uint32_t baud)
{
uint32_t mantissa, fraction;
RCC->APB2ENR |= 1 << 4; //GPIOA
RCC->APB1ENR |= 1 << 17; //USART1
GPIOA->CRL &= ~(0xF << 8);
GPIOA->CRL |= 3 << 8;
GPIOA->CRL |= 2 << 10; //PA2
GPIOA->CRL &= ~(0xF << 12);
GPIOA->CRL |= 1 << 14; //PA3
USART2->CR1 &= ~(1 << 12); //8x1
USART2->CR1 &= ~(1 << 10); //no parity
USART2->CR1 |= 1 << 5; //rx not empty interrupt
USART2->CR1 |= 1 << 3; //tx enable
USART2->CR1 |= 1 << 2; //rx enable
USART2->CR2 &= ~(3 << 12); //1 stop bit
mantissa = 36000000 / baud / 16;
fraction = (uint32_t)((float)36000000 / baud - mantissa);
USART2->BRR = (mantissa << 4) | fraction;
USART2->CR1 |= 1 << 13; //enable
nvic_init(USART2_IRQn, 1, 3, 2);
}
void USART2_IRQHandler(void)
{
uint8_t tmp;
if(USART2->SR & (1 << 5))
{
tmp = USART2->DR;
USART2->DR = tmp;
}
}
- 基本定时器的使用
void tim2_init(void)
{
RCC->APB1ENR |= 1 << 0; //TIM2
TIM2->CR1 |= 1 << 7; //ARR Preload
TIM2->CR1 &= ~(1 << 4); //count up
TIM2->ARR = 10000 - 1;
TIM2->PSC = 7200 - 1;
TIM2->DIER |= 1 << 0; //Update interrupt
TIM2->CR1 |= 1 << 0; //enable
nvic_init(TIM2_IRQn, 1, 2, 2);
}
void TIM2_IRQHandler(void)
{
if(TIM2->SR & (1 << 0))
{
TIM2->SR &= ~(1 << 0);
GPIOD->ODR ^= 1 << 2;
}
}
- RTC秒中断
void rtc_init(void)
{
RCC->APB1ENR |= 1 << 28; //power clock
RCC->APB2ENR |= 1 << 27; //backup
PWR->CR |= 1 << 8; //rtc protection
RCC->BDCR |= 1 << 16; //reset
RCC->BDCR &= ~(1 << 16); //clear reset flag
RCC->BDCR |= 1 << 0;
while(!(RCC->BDCR & (1 << 1)));
RCC->BDCR |= 1 << 8; //LSE as RTC clock
RCC->BDCR |= 1 << 15; //rtc clock enable
while(!(RTC->CRL & (1 << 3))); //wait RTC ready
RTC->CRL |= 1 << 4; //go to configurtation mode
while(!(RTC->CRL & (1 << 5))); //wait RTC oeperation OFF
RTC->PRLL = 0x9C39;
while(!(RTC->CRL & (1 << 5))); //wait RTC oeperation OFF
RTC->CRH |= 1 << 0; //second interrupt
while(!(RTC->CRL & (1 << 5))); //wait RTC oeperation OFF
nvic_init(RTC_IRQn, 1, 1, 2);
}
void RTC_IRQHandler(void)
{
if(RTC->CRL & (1 << 0))
{
RTC->CRL &= ~(1 << 0);
while(!(RTC->CRL & (1 << 5))); //wait RTC oeperation OFF
GPIOD->ODR ^= 1 << 2;
}
}
- IIC
void iic_init(void)
{
RCC->APB2ENR |= 1 << 4; //GPIOC
GPIOC->CRH &= ~(0xF << 12);
GPIOC->CRH |= 3 << 12;
GPIOC->CRH |= 1 << 14; //PC11
GPIOC->CRH &= ~(0xF << 16);
GPIOC->CRH |= 3 << 16;
GPIOC->CRH |= 1 << 18; //PC12 Open drain
GPIOC->ODR |= 1 << 11;
GPIOC->ODR |= 1 << 12;
}
void iic_start(void)
{
IIC_SDA = 1;
IIC_SCL = 1;
delay_us(2);
IIC_SDA = 0;
delay_us(2);
IIC_SCL = 0;
}
void iic_stop(void)
{
IIC_SDA = 0;
IIC_SCL = 0;
delay_us(2);
IIC_SCL = 1;
delay_us(2);
IIC_SDA = 1;
}
void iic_send_byte(uint8_t byte)
{
IIC_SCL = 0;
for(uint8_t i = 0; i < 8; i++)
{
IIC_SDA = (byte >> 7) & 0x1;
byte <<= 1;
delay_us(2);
IIC_SCL = 1;
delay_us(2);
IIC_SCL = 0;
delay_us(2);
}
}
uint8_t iic_recv_byte(void)
{
uint8_t tmp;
for(uint8_t i = 0; i < 8; i++)
{
IIC_SCL = 0;
delay_us(2);
IIC_SCL = 1;
tmp <<= 1;
if(SDA_READ == 1)
{
tmp += 1;
}
delay_us(2);
}
iic_ack();
return tmp;
}
void iic_ack(void)
{
IIC_SCL = 0;
IIC_SDA = 0;
delay_us(2);
IIC_SCL = 1;
delay_us(2);
IIC_SCL = 0;
}
void iic_no_ack(void)
{
IIC_SCL = 0;
IIC_SDA = 1;
delay_us(2);
IIC_SCL = 1;
delay_us(2);
IIC_SCL = 0;
}
uint8_t iic_wait_ack(void)
{
uint8_t time_out;
IIC_SDA = 1;
delay_us(2);
IIC_SCL = 1;
delay_us(2);
while(SDA_READ)
{
if(time_out++ > 250)
{
iic_stop();
return 1;
}
}
IIC_SCL = 0;
return 0;
}
- SPI
void spi_init(void)
{
RCC->APB2ENR |= 1 << 2;
RCC->APB2ENR |= 1 << 12;
GPIOA->CRL &= ~(0xF << 20);
GPIOA->CRL |= 3 << 20; //SCK
GPIOA->CRL |= 2 << 22;
GPIOA->CRL &= ~(0xF << 24);
GPIOA->CRL |= 2 << 26;
GPIOA->ODR |= 1 << 6; //MISO input
GPIOA->CRL |= ~((uint32_t)0xF << 28);
GPIOA->CRL |= (uint32_t)2 << 30;
GPIOA->CRL |= (uint32_t)3 << 28; //MOSI output
SPI1->CR1 |= 1 << 15; //bidirection
SPI1->CR1 &= ~(1 << 11); //8bit
SPI1->CR1 |= 1 << 9; //soft
SPI1->CR1 |= 1 << 8; //SSI
SPI1->CR1 &= ~(1 << 7); //MSB
SPI1->CR1 |= 2 << 3; //BAUD
SPI1->CR1 |= 1 << 2; //Master
SPI1->CR1 &= ~(1 << 1); //CPOL low
SPI1->CR1 &= ~(1 << 0); //CPHA low
SPI1->CR1 |= 1 << 6; //enable
}
uint8_t spi_write_read_byte(uint8_t byte)
{
while(!(SPI1->SR & (1 << 1)))
{
}
SPI1->DR = byte;
while(!(SPI1->SR & (1 << 0)))
{
}
return SPI1->DR;
}