CH32V003的输入/输出端口

发布时间 2023-08-19 12:50:39作者: fxzq

GPIO端口是处理器与外部设备打交道的基础,为了更好地应用它,下面就对CH32V003的通用输入输出端口(GPIO)的寄存器结构及用法做详细深入地讨论。
CH32V003是一个32位的处理器,但它的GPIO端口并不是把32个引脚都引出来,而是根据芯片型号及其封装的不同,分别引出来了18个(CH32V003F4P6、CH32V003F4U6)、14个(CH32V003A4M6)和6个(CH32V003J4M6)I/O引脚。所有GPIO端口引脚都可以配置成多种输入或输出模式,内置有可关闭的上拉或下拉电阻,可配置成推挽或开漏功能。此外,GPIO端口的引脚还具有其他复用功能。

CH32V003GPIO端口的每个引脚都可以配置成浮空输入、上拉输入、下拉输入、模拟输入、开漏输出、推挽输出以及复用功能的输入和输出等模式。以下是一个I/O引脚的基本结构框图。

从上图中可以看出,每个引脚在芯片内部都有两只保护二极管,I/O口内部可分为输入和输出驱动模块。其中输入驱动有弱上下拉电阻可选,可连接到A/D等模拟输入的外设;如果输入到数字外设,就需要经过一个TTL施密特触发器,再连接到GPIO输入寄存器或其他复用外设。输出驱动有一对MOS管,可通过配置上下的MOS管是否使能来将I/O引脚配置成开漏或推挽输出;输出驱动内部也可以配置成由GPIO控制输出还是由复用的其他外设控制输出。

芯片在复位后,GPIO端口处于初始状态,这时大多数I/O引脚都运行在浮空输入状态。

下表给出了与GPIO端口配置相关的寄存器信息,一共有18个。这些寄存器必须以字(32位)的方式来操作。

先来看端口配置寄存器低位R32_GPIOx_CFGLR,该类寄存器一共有3个,即x的值分别为A、C、D的3个。它们分别针对3组不同的I/O端口,其结构完全相同。此外,由于CH32V003芯片的引脚较少,所以在该芯片中并没有定义端口配置寄存器的高位(即R32_GPIOx_CFGHR)。下面是R32_GPIOx_CFGLR寄存器的全部位结构。

(1)第31~30、27~26、23~22、19~18、15~14、11~10、7~6及3~2等每两位分别为CNF7、CNF6、CNF5、CNF4、CNF3、CNF2、CNF1、CNF0等8个引脚的配置位(分别对应7~0号引脚)。当端口处于输入模式时,CNF值为00时表示对应的引脚为模拟输入模式,为01时表示浮空输入模式,为10时表示带有上下拉电阻模式。当端口处于输出模式时,CNF的值为00时表示对应的引脚为通用推挽输出模式,为01时表示通用开漏输出模式,为10时表示复用功能推挽输出模式,值为11时表示复用功能开漏输出模式。默认值为01,即在输入时是浮空输入,在输出时是开漏输出。
(2)第29~28、25~24、21~20、17~16、13~12、9~8、5~4及1~0等每两位分别是MODE7、MODE6、MODE5、MODE4、MODE3、MODE2、MODE1、MODE0等8个引脚模式的选择位(分别对应7~0号引脚)。MODE的值为00时表示对应的引脚为输入模式,为01时表示引脚为最大速度10MHz的输出模式,为10时表示引脚为最大速度2MHz的输出模式,值为11时表示引脚为最大速度50MHz的输出模式。默认为输入模式。

从上面可以看出,在端口配置寄存器低位R32_GPIOx_CFGLR中,通过每相邻的4个位来确定一个引脚的状态,8个引脚刚好用了32位,配置起来也很方便。在芯片复位后,每个引脚都处于浮空输入状态,这样做的好处也是显而易见的,即不会对与引脚相连的外部设备产生任何影响。

接下来看端口输入寄存器GPIOx_INDR,该类寄存器也有3个,即x的值分别为A、C、D的3个。它们分别针对3组不同的I/O端口,其结构完全相同。下面是GPIOx_INDR寄存器的全部位结构。

(1)第31~8位均为保留位。
(2)第7~0位分别对应IDR7~IDR0等8个引脚输入位,这些位为只读属性,用于获取端口数据,但只能以16位形式读出,读出的值就是对应引脚上的高低电平状态。

接下来是端口输出寄存器GPIOx_OUTDR,该类寄存器一共有3个,即x的值分别为A、C、D的3个。它们分别针对3组不同的I/O端口,其结构完全相同。下面是GPIOx_OUTDR寄存器的全部位结构。

(1)第31~8为保留位。
(2)第7~0位分别对应ODR7~ODR0等8个引脚输出位。当端口处于输出状态时,用于输出该寄存器的值(即对应引脚上产生高低电平),但只能以16位形式操作。当端口处于输入状态时,用于设定上下拉电阻,置0时设置成下拉输入方式,置1时设置成上拉输入方式。 

接着看端口复位/置位寄存器GPIOx_BSHR, 该类寄存器也是一共3个,即x的值分别为A、C、D的3个。它们分别针对3组不同的I/O端口,其结构完全相同。下面是GPIOx_BSHR寄存器的全部位结构。

(1)第31~24及其后面的15~8位均为保留位。
(2)第23~16位分别对应BR7~BR0这8个清除位,这些位为只写属性。对这些位置1会清除对应的ODR位(引脚变低电平),写0无影响。这些位只能以16 位(高16位)的形式操作。
(3)第7~0位分别对应BS7~BS0这8个置位位,这些位为只写属性。对这些位置1会使对应的ODR位置1(引脚变高电平),写0无影响。这些位只能以16 位(低16位)的形式操作。如果同时设置了BR和BS位,则BS位起作用。 

接下来看端口复位寄存器GPIOx_BCR,该类寄存器一共有3个,即x的值分别为A、C、D的3个。它们分别针对3组不同的I/O端口,其结构完全相同。下面是GPIOx_BCR寄存器的全部位结构。

(1)第31~8位均为保留位。
(2)第7~0位分别对应BR7~BR0这8个清除位,这些位为只写属性。对这些位置1会清除对应的ODR位(引脚变低电平),写0无影响。这些位只能以16 位形式操作。

最后来看配置锁定寄存器GPIOx_LCKR,该类寄存器也有3个,即x的值分别为A、C、D的3个。它们分别针对3组不同的I/O端口,其结构完全相同。下面是GPIOx_LCKR寄存器的全部位结构。

(1)第31~9位均为保留位。
(2)第8位(LCKK)为锁定键,它通过特定的序列写入来实现锁定。它的值可以随时读出,值为0时表示未锁定,值为1时表示已锁定。锁定键的写入序列为:写1-写0-写1-读0-读1,最后的读1非必要,但可以用来确认锁定键已经激活。锁定生效后,只有在下次复位后才能更改端口的配置。
(3)第7~0位分别对应LCK7~LCK0这8个锁定位。这些位为1时表示锁定对应端口引脚的配置,锁定的是配置寄存器低位GPIOx_CFGLR的配置。注意,只能在LCKK(第8位)未激活前改变这些位的值。

从上述讨论中可以看到,端口操作可以通过INDR、OUTDR、BSHR和BCR等寄存器来实现。那应该如何选择呢?一般地,如果直接读端口引脚上的电平,使用INDR寄存器;如果读取的是端口数据寄存器,使用OUTDR寄存器;如果要写引脚电平,首先推荐使用BSHR寄存器,如果要实现端口的读—改—写操作(比如取反),可使用OUTDR寄存器,BCR寄存器一般就不用了。当然,具体如何使用还是要具体分析,不能一概而论。但有一点要注意,尽量避免使用OUTDR,因为在操作它的过程中,有被中断打断的风险,如果要用最好在操作之前关闭所有中断,用完后再打开。 

小结一下使用GPIO端口的常规步骤,如下:
1、配置APB2PCENR寄存器,使能相应端口的时钟;
2、配置相应端口的CFGLR寄存器,设置引脚的模式和速度等;
3、输出时操作相应端口的BSHR寄存器,输入时操作INDR寄存器;
4、端口取反时,可操作OUTDR寄存器。