感谢沁恒的开发板用于学习,通过学习CH32来掌握标准库函数,虽然stm32现在都在主推HAL库,国产32还是在使用标注库,通过学习ch32来巩固标注库的相关内容。ch32与stm32高度相似,GPIO内部结构一样,对于内部原理不在一一概述,重点对标准库函数进行记录。
CH32F205/7系列是基于Cortex-M3内核设计的工业级互联型微控制器,此系列主频高达144MHz,独立了GPIO电压(与系统供电分离)。资源同比增加了随机数单元,4组运放比较器;提高串口UART数量到8组,电机定时器到4组。搭配时钟安全、电源管理、双组DMA、DAC、SDIO、CAN、FSMC等资源。提供USB2.0高速接口(480Mbps)并内置了PHY收发器,以太网MAC升级到千兆并集成了10M-PHY模块。(其中ADC为16位,之前使用过的stm32f446只有12位,不知道stm32有没有16位ADC的单片机)
GPIO(general porpose intput output):通用输入输出端口的简称。可以通过软件控制其输出和输入。stm32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通信,控制以及数据采集的功能。
GPIO_Init( GPIO_TypeDef GPIOx, GPIO_InitTypeDefGPIO_InitStruct )
void GPIO_Init( GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct )
{
uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
uint32_t tmpreg = 0x00, pinmask = 0x00;
currentmode = ( ( uint32_t )GPIO_InitStruct->GPIO_Mode ) & ( ( uint32_t )0x0F );
if( ( ( ( uint32_t )GPIO_InitStruct->GPIO_Mode ) & ( ( uint32_t )0x10 ) ) != 0x00 )
{
currentmode |= ( uint32_t )GPIO_InitStruct->GPIO_Speed;
}
#if defined (CH32F20x_D6)
if(((*(uint32_t *) 0x40022030) & 0x0F000000) == 0)
{
MCU_Version = 1;
}
if((GPIOx == GPIOC) && MCU_Version){
GPIO_InitStruct->GPIO_Pin = GPIO_InitStruct->GPIO_Pin >> 13;
}
#endif
if( ( ( uint32_t )GPIO_InitStruct->GPIO_Pin & ( ( uint32_t )0x00FF ) ) != 0x00 )
{
tmpreg = GPIOx->CFGLR;
for( pinpos = 0x00; pinpos < 0x08; pinpos++ ){
pos = ( ( uint32_t )0x01 ) << pinpos;
currentpin = ( GPIO_InitStruct->GPIO_Pin ) & pos;
if( currentpin == pos )
{
pos = pinpos << 2;
pinmask = ( ( uint32_t )0x0F ) << pos;
tmpreg &= ~pinmask;
tmpreg |= ( currentmode << pos );
if( GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD )
{
GPIOx->BCR = ( ( ( uint32_t )0x01 ) << pinpos );
}
else
{
if( GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU )
{
GPIOx->BSHR = ( ( ( uint32_t )0x01 ) << pinpos );
}
}
}
}
GPIOx->CFGLR = tmpreg;
}
if( GPIO_InitStruct->GPIO_Pin > 0x00FF )
{
tmpreg = GPIOx->CFGHR;
for( pinpos = 0x00; pinpos < 0x08; pinpos++ ){
pos = ( ( ( uint32_t )0x01 ) << ( pinpos + 0x08 ) );
currentpin = ( ( GPIO_InitStruct->GPIO_Pin ) & pos );
if( currentpin == pos )
{
pos = pinpos << 2;
pinmask = ( ( uint32_t )0x0F ) << pos;
tmpreg &= ~pinmask;
tmpreg |= ( currentmode << pos );
if( GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD )
{
GPIOx->BCR = ( ( ( uint32_t )0x01 ) << ( pinpos + 0x08 ) );
}
if( GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU )
{
GPIOx->BSHR = ( ( ( uint32_t )0x01 ) << ( pinpos + 0x08 ) );
}
}
}
GPIOx->CFGHR = tmpreg;
}
}
GPIO_Init()函数为GPIO的初始化函数,函数里有两个参数,GPIOx(显而易见x为任一项)用于指定那一组IO口,第二个参数为初始化参数结构体指针,结构体类型为 GPIO_InitTypeDef,用结构体来定义GPIO的相关参数。
结构体相关成员:
typedef struct
{
uint16_t GPIO_Pin; /* 指明GPIO的引脚
This parameter can be any value of @ref GPIO_pins_define */
GPIOSpeed_TypeDef GPIO_Speed; /* GPIO的引脚速度.
This parameter can be a value of @ref GPIOSpeed_TypeDef */
GPIOMode_TypeDef GPIO_Mode; /* 指明GPIO的引脚模式.
This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;
GPIO_Speed:GPIO_Speed_10MHz, GPIO_Speed_2MHz, GPIO_Speed_50MHz
GPIO_Mode:
GPIO_Mode_AIN = 0x0, //模拟输入
GPIO_Mode_IN_FLOATING = 0x04, //浮空输入
GPIO_Mode_IPD = 0x28, //下拉输入
GPIO_Mode_IPU = 0x48, //上拉输入
GPIO_Mode_Out_OD = 0x14, //开漏输出
GPIO_Mode_Out_PP = 0x10, //通用推挽输出
GPIO_Mode_AF_OD = 0x1C, //复用开漏输出
GPIO_Mode_AF_PP = 0x18 //复用推挽码片`
代码如下(示例):
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE,ENABLE); //使能 PB,PE 端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1-->PE.5 推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_5); //PE.5 输出高
}
void GPIO_DeInit(GPIO_TypeDef* GPIOx);//释放初始化
void GPIO_AFIODeInit(void);
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);//初始化函数
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//读取输入模式管脚的电平
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);//读取输入模式GPIO一组的电平
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//读取输出模式管脚的电平
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);//读取输出模式GPIO一组的电平
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//设置管脚的电平为高电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//设置管脚的电平为低电平
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);//写管脚的高低电平
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);//写GPIO一组的电平
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_EventOutputCmd(FunctionalState NewState);//
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);
//PE5间断点亮LED
int main( void )
{
u8 i = 0;
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 );
Delay_Init();
USART_Printf_Init( 115200 );
LED_Init();
// printf( "SystemClk:%d\r\n", SystemCoreClock );
// printf( "GPIO Toggle TEST\r\n" );
// GPIO_Toggle_INIT();
while( 1 )
{
Delay_Ms(250);
LED1=!LED1;
}
}
工程源码