我是STM32的新手,不是嵌入式开发(使用PIC,dsPIC,MSP430)。
我正在尝试使用直接寄存器操作编写基本库(STMCube HAL很酷,但我发现无论如何我必须阅读数据表,因此首选寄存器操作)。实质上,我只是试图使Blue Pill
开发板上的LED闪烁,即C13
引脚。
我可以编译,闪存和调试,但是当我调试时,LED没有闪烁,寄存器也没有变化。寄存器值本身实际上并不重要,因此您不需要出去检查数据表。我只需要能够操纵它们!
单步执行调试器工作正常,variables
观察窗口也会正确更新。
虽然这不是详尽无遗的(已经有几个小时了,所以我可能忘了包括一些),这些是我尝试过的一些事情:
BOOTx
引脚配置所有人都有相同的结果。我怀疑我可能会遗漏CMSIS中的某些内容或必要的包含文件,我似乎无法找到它。
我可能遗漏的另一点涉及振荡器设置。据我了解,启动时有一个默认配置,我不必担心,除非我想改变它。也许这有缺陷?
当我尝试使用STM32CUBEMX HAL进行基本切换时,它可以工作。这让我觉得在包含,项目设置,振荡器设置等方面我缺少一些基本的东西?
#include "gpio.h"
#define LED_PIN 13
int main(void)
{
uint32_t i;
// initialize the peripherals
GPIO_init();
GPIOC_setupOutput(LED_PIN, PUSH_PULL, PIN_SPEED_50MHz);
while(1)
{
GPIOC_setPin(LED_PIN);
for(i=0; i<4000000; i++);
GPIOC_clearPin(LED_PIN);
for(i=0; i<4000000; i++);
}
}
#ifndef _GPIO_H
#define _GPIO_H
#include <stdint.h>
#include <stdbool.h>
typedef enum{
ANALOG=0b00, FLOATING=0b01, PULL_UP_PULL_DOWN=0b10
}InputPinMode;
typedef enum{
PUSH_PULL=0b00, OPEN_DRAIN=0b01, AF_PUSH_PULL=0b10, AF_OPEN_DRAIN=0b11
}OutputPinMode;
typedef enum{
PIN_SPEED_2MHz=0b10, PIN_SPEED_10MHz=0b01, PIN_SPEED_50MHz=0b11
}PinSpeed;
void GPIO_init(void);
void GPIOA_setupInput(uint8_t pinNumber, InputPinMode mode);
void GPIOC_setupInput(uint8_t pinNumber, InputPinMode mode);
void GPIOA_setupOutput(uint8_t pinNumber, OutputPinMode mode, PinSpeed speed);
void GPIOC_setupOutput(uint8_t pinNumber, OutputPinMode mode, PinSpeed speed);
bool GPIOA_readPin(uint8_t pinNumber);
void GPIOA_setPin(uint8_t pinNumber);
void GPIOC_setPin(uint8_t pinNumber);
void GPIOA_clearPin(uint8_t pinNumber);
void GPIOC_clearPin(uint8_t pinNumber);
#endif
#include "stm32f1xx.h"
#include "gpio.h"
/**
* @brief Initialize GPIO
*/
void GPIO_init(void){
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPDEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPEEN;
}
/**
* @brief Setup pin as an input
* @param pinNumber the pin number
* @param mode the input mode
*/
void GPIOA_setupInput(uint8_t pinNumber, InputPinMode mode){
uint32_t pinNumberLocation, regValue;
if(pinNumber < 8){
pinNumberLocation = pinNumber << 2; // bit location
regValue = (mode << 2) << pinNumberLocation;
GPIOA->CRL &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOA->CRL = regValue;
}else{
pinNumberLocation = (pinNumber - 8) << 2; // bit location
regValue = (mode << 2) << pinNumberLocation;
GPIOA->CRH &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOA->CRH = regValue;
}
}
/**
* @brief Setup port A pin as an output
* @brief pinNumber the pin number
* @brief mode the output mode
* @brief speed the pin speed (lower results in less noise)
*/
void GPIOA_setupOutput(uint8_t pinNumber, OutputPinMode mode, PinSpeed speed){
uint32_t pinNumberLocation, regValue;
if(pinNumber < 8){
pinNumberLocation = pinNumber << 2; // bit location
regValue = ((mode << 2) << pinNumberLocation) + speed;
GPIOA->CRL &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOA->CRL |= regValue;
}else{
pinNumberLocation = (pinNumber - 8) << 2; // bit location
regValue = ((mode << 2) << pinNumberLocation) + speed;
GPIOA->CRH &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOA->CRH |= regValue;
}
}
/**
* @brief Setup port C pin as an output
* @brief pinNumber the pin number
* @brief mode the output mode
* @brief speed the pin speed (lower results in less noise)
*/
void GPIOC_setupOutput(uint8_t pinNumber, OutputPinMode mode, PinSpeed speed){
uint32_t pinNumberLocation, regValue;
if(pinNumber < 8){
pinNumberLocation = pinNumber << 2; // bit location
regValue = ((mode << 2) << pinNumberLocation) + speed;
GPIOC->CRL &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOC->CRL |= regValue;
}else{
pinNumberLocation = (pinNumber - 8) << 2; // bit location
regValue = ((mode << 2) << pinNumberLocation) + speed;
GPIOC->CRH &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOC->CRH |= regValue;
}
}
bool GPIOA_readPin(uint8_t pinNumber){
uint16_t mask = 1 << pinNumber;
if(GPIOA->IDR & mask)
return true;
else
return false;
}
void GPIOA_setPin(uint8_t pinNumber){ GPIOA->BSRR = (1 << pinNumber);}
void GPIOC_setPin(uint8_t pinNumber){ GPIOC->BSRR = (1 << pinNumber);}
void GPIOA_clearPin(uint8_t pinNumber){ GPIOA->BSRR = ~(1 << (pinNumber + 16));}
void GPIOC_clearPin(uint8_t pinNumber){ GPIOC->BSRR = ~(1 << (pinNumber + 16));}
答案 0 :(得分:1)
你的问题很简单。
您忘了启用外设时钟。默认情况下,Cortex micro中的所有外设时钟都处于关闭状态。请阅读参考手册而非数据表。查找 &#34;外设时钟使能寄存器&#34; 并启用正确的GPIO端口。
PS在您的情况下RCC_APB2ENR
你在代码中犯了很多其他严重的错误。我没有时间完全读取,但BSRR BRR寄存器是只写的,你不能做任何引起读取的操作(即| =或&amp; =)。可能还有更多。仔细阅读RM。另一个错误 - 你写信给BRR的保留部分。 (保留高16位)如果你甚至写入注册表的正确一半,你的&amp; =〜()操作会做出与你想象的不同的事情(从非法的读操作中抽象出来) - 它什么都不做。实际上你根本没有阅读和理解RM
所以对于未来: Cortex micro可以访问外设寄存器 - 启动它们的时钟。即使EXTI(外部中断)也是外设,它的时钟也必须启用。
有些外设有多个时钟可供使用(例如STM32F3xx中的ADC,其中模拟部分有多个时钟选项,必须单独启用+数字部分)
答案 1 :(得分:1)
PB2上的二极管 - 工作代码
volatile uint32_t delay;
#include "stm32f10x.h"
int main(void)
{
RCC->APB2ENR = RCC_APB2ENR_IOPBEN;
GPIOB->CRL |= GPIO_CRL_MODE2_1;
GPIOB->CRL &= ~GPIO_CRL_CNF2_0;
while(1)
{
GPIOB->ODR |= GPIO_ODR_ODR2; //or GPIO_ODR_2 depending of the .h header version
for(delay = 2000000; delay; delay--);
GPIOB->ODR &= ~GPIO_ODR_ODR2; //or GPIO_ODR_2 depending of the .h header version
for(delay = 2000000; delay; delay--);
GPIOB->BSRR = 1 << 2;
for(delay = 2000000; delay; delay--);
GPIOB->BSRR = 1 << (2 + 16);
for(delay = 2000000; delay; delay--);
}
} // change