六、我要的是开关
上面的分析和代码,看似有理有据,实则乱七八糟。一团乱麻算不上,顶多一个P。
文字上把U1 MCU假设成开关,代码上没体现。这种想法,符合我们的天然思路,是面向对象的思维。从这句开始,我们走上OOP,构建我们的葫芦世界,使用C++的语言了。
我们想要的是个开关,就创造一个开关,开关听招呼就行。具体开关怎么实现,由开关自己解决。
今天的开关实现很简单,当然有很多方法。选天然思维来,OOP方法。构建每一个对象,然后按照依赖关系合并。
算上开关,一个四个对象。我们分析和合并一下,一个开关,各对应一个ODR、CR和APB2ENR。这里我不考虑怎么变化,所以另外三个对象,可以成为开关的属性成员。合并后的开关对象,成了这样:
终于有了点自己的葫芦长出来的感觉,下面上代码。
//为了简洁,不包含任何头文件
//体现面向对象的版本
//用 C++ 语言和参考手册的寄存器编写程序
//修电视的老五 2024-9-12
/***********************************************************************************/
#define uint32_t unsigned int
#define uint16_t unsigned short
//代表图1中“我们”的类
class We;
//代表图1中“开关”的类
class KnifeSwitch;
int main();
/***********************************************************************************/
class We{
public:
//图1, 需要是呼唤开关
void Need(KnifeSwitch& knife_switch);
};
class KnifeSwitch{
public:
//开关只接受开和关两种呼唤
enum call_enum{ OPEN, CLOSE };
//图1中的呼唤
void Call( enum call_enum need );
KnifeSwitch();
private:
//图2中的ODR,CR,APB2ENR,合并后成为
//图3中的三个地址
volatile uint32_t *odr_addr;
volatile uint32_t *cr_addr;
volatile uint32_t *apb2enr_addr;
};
/***********************************************************************************/
void We::Need(KnifeSwitch& knife_switch)
{
//需要就是开关
knife_switch.Call(KnifeSwitch::OPEN);
knife_switch.Call(KnifeSwitch::CLOSE);
}
/***********************************************************************************/
KnifeSwitch::KnifeSwitch()
{
//初始化三个地址表示的对象
odr_addr = (uint32_t*) (0x40000000 + 0x10000 + 0x0800 + 0x0c);
cr_addr = (uint32_t*) (0x40000000 + 0x10000 + 0x0800 + 0x00);
apb2enr_addr = (uint32_t*) (0x40000000 + 0x20000 + 0x1000 + 0x18);
//APB2ENR对象,开启GPIOA的时钟
const uint32_t gpioa_clk_enable = 0x04;
*apb2enr_addr |= gpioa_clk_enable;
//CR对象,配置PIN 0 为输出开漏模式
const uint32_t gpio_pin_0_config = 0x02;
uint32_t temp;
temp = *cr_addr, temp &= 0xfffffff0, temp |= gpio_pin_0_config, *cr_addr = temp;
}
void KnifeSwitch::Call( enum call_enum need )
{
//我们的电路是高电平关闭,低电平开启
const uint16_t gpio_pin_off = 0x0001;
if( need == CLOSE )
//ODR对象的操作
*odr_addr &= ~gpio_pin_off;
else
//ODR对象的操作
*odr_addr |= gpio_pin_off;
}
int main()
{
//图1,我们和开关都有了
KnifeSwitch knife_switch;
We we;
while(1)
{
//图1,需要呼唤开关
we.Need(knife_switch);
}
return 0;
}
和上篇的代码比较,有整齐了的感觉,小葫芦长了出来。
这个葫芦种出来,有很多的叶子,需要修剪。很无奈的,我们从小就见多了这种化简,以数学最多。加减乘除的混合运算式,计算一元二次方程,计算方程组,计算三角函数,求值,求长度,求体积。。。。。。求心理阴影面积。
总算被孙子打了,现在世界真不像样!