五、看图写话
网上有句老话:无图无真相(没图你说个J8)。
我想把开发板的照片发上来,拍了又发现太多的无关要素,末得灵魂。所以有趣的图片发上来:
别嫌弃啊,将就着吧。说不定有新的发现,请细品。
同一部名著,有86版的《西游记》,九五年的《大话西游》,两千年的《悟空传》和今天的《黑神话 悟空》。。。。。。
我们从图1中分析,发现电路还可以简化成:
图1中的U1 MCU可以简化成一个开关。当U1的开关开启,电路中无电流通过,灯不亮。当U1简化的开关闭合时,电路中的电流 i = u/r = (3.3-1.7)/470 = 3.40mA。灯亮,完美!
那U1 MCU怎么成为能跑3.4mA的开关呢?
能当开关的场管的脚,都长在GPIO里
这个场管,由叫ODR的输出数据寄存器控制。继续寻找ODR能用的前提
ODR能用,依赖CR寄存器里的MODE位设置成输出,CNF位设置成普通输出。而ODR和CR寄存器放在某个GPIO口里。GPIO口能用,又依赖RCC里APB2ENR寄存器的相应的GPIO时钟开启。
一张图引出多张图,成了用图说图。下面用C语言写出程序的话:
//为了简洁,不包含任何头文件
//用 C 语言和参考手册的寄存器编写程序
//修电视的老五 2024-9-11
/***********************************************************************************/
#define uint32_t unsigned int
#define uint16_t unsigned short
void Tu2(int on);
void Tu4();
int main();
/***********************************************************************************/
//对照图4,实现ODR相关的配置
void Tu4()
{
{
//开启GPIOA的时钟
//APB2ENR的寄存器,只在这里使用。
volatile uint32_t* apb2_enr = (uint32_t*)( 0x40000000 + 0x20000 + 0x1000 + 0x18 );
const uint32_t gpioa_clk_enable = 0X04;
*apb2_enr |= gpioa_clk_enable;
}
{
//配置MODE=输出,CNF=普通输出
//GPIOA的CR寄存器,只在这里局部使用
volatile uint32_t* gpioa_cr = (uint32_t*)( 0x40000000 + 0x10000 + 0x0800 + 0x00 );
const uint32_t gpio_pin_0_config = 0x02;
//GPIOA的复位值不是0,所以这么处理一下
uint32_t temp;
temp = *gpioa_cr;
temp &= 0xfffffff0;
temp |= gpio_pin_0_config;
*gpioa_cr= temp;
}
}
//对照图2,实现用on参数控制ODR的开关。
// on == 0,关闭。其他开启
void Tu2(int on)
{
volatile uint32_t* gpioa_odr = (uint32_t*)( 0x40000000 + 0x10000 + 0x0800 + 0x0c );
//我们的电路是高电平关闭,低电平开启
const uint16_t gpio_pin_off = 0x0001;
if( on )
*gpioa_odr &= ~gpio_pin_off;
else
*gpioa_odr |= gpio_pin_off;
}
int main()
{
//分析是从图1到图4,按照依赖关系,执行时从图4到图1。
Tu4();
while(1)
{
Tu2( 1 );
Tu2( 0 );
}
return 0;
}