主页 > 软件开发  > 

STM32各外设初始化步骤


1、GPIO初始化步骤

        1、使能GPIO时钟

        2、初始化GPIO的输入/输出模式

        3、设置GPIO的输出值或获取GPIO的输入值

GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); 2、EXTI的初始化步骤

        1、使能EXTI线所在的GPIO时钟和AFIO复用时钟

        2、初始化EXTI线所在的GPIO的输入输出模式

        3、将GPIO脚映射到对应的EXTI线上

        4、设置NVIC优先级分组,初始化NVIC

        5、初始化EXTI

GPIO_InitTypeDef GPIO_InitStruct; EXTI_InitTypeDef EXTI_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_Pin_1); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStruct.NVIC_IRQChannel = EXTI1_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStruct); EXTI_InitStruct.EXTI_Line = EXTI_Line1; EXTI_InitStruct.EXTI_LineCmd = ENABLE; EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_Init(&EXTI_InitStruct); 3、USART的初始化步骤

        1、使能USARTx的时钟和USARTx输入输出所用的GPIO时钟

        2、将USART使用的GPIO引脚初始化为复用推挽(输出)和浮空输入模式

        3、初始化USARTx,设置各种属性

        4、如果需要中断,则开启串口中断

        5、如果设置了USART中断,则需要设置NVIC优先级分组并且初始化NVIC

        6、使能USARTx

GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_Init(USART1,&USART_InitStruct); USART_Cmd(USART1,ENABLE); USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //中断接收 NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStruct); void USART1_IRQHandler(void) { //中断处理函数 } 4、通用定时器TIM定时中断的初始化步骤

        1、使能定时时钟

        2、初始化时基单元

        3、开启定时器中断

        4、配置NVIC:优先级分钟及NVIC初始化

        5、使能定时器

        6、编写定时中断函数

计数初值计算公式:计数器在CK_CNT的驱动下,计下一个数的时间为CK_CLK的倒数,即1 / (TIMxCLK / (PSC + 1));从开始计数到溢出期间计数器加1的个数为ARR + 1。(TIMxCLK:定时器时钟频率,默认等于系统时钟频率)

计数器计数频率  CK_CNT = TIMxCLK / (PSC + 1)

计数器溢出频率 CK_CNT_OV = CK_CNT / (ARR + 1)

                                                  = TIMxCLK / (PSC + 1) / (ARR + 1)

time(溢出时间) =  ARR + 1 /TIMxCLK/ PSC + 1

以100ms,系统时钟为72MHZ为例,计算ARR和PSC的值,带入公式可得。

(ARR + 1) X (PSC + 1) = 100 *  72 * 1000

得 

(ARR + 1) X (PSC + 1) = 1000  *  7200

这样可得多种组合,如ARR = 999 ; PSC = 7199。

//以100ms为例配置TIM定时中断 TIM_TimeBaseInitTypeDef TimeBaseInitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); TimeBaseInitStruct.TIM_Period = 999 + 1; //自动重装值 TimeBaseInitStruct.TIM_Prescaler = 7199 + 1; //预分频值 TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分割 TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // TimeBaseInitStruct.TIM_RepetitionCounter = ; 重复计数值 pwm模式使用 TIM_TimeBaseInit(TIM3,&TimeBaseInitStruct); TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除标志位,防止从1开始计数 TIM_ITConfig(TIM3,ENABLE); //使能定时中断 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分钟 NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStruct); TIM_Cmd(TIM3,ENABLE); void TIM3_IRQHandler(void) { if(TIM_GetFlagStatus(TIM3,TIM_IT_Update) != RESET) //判断更新中断是否发生 { //业务代码 TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除标志位 } } 5、通用定时器PWM输出初始化步骤

        1、使能定时器时钟和相关GPIO的时钟

        2、初始化GPIO为复用推挽输出

        3、若将PWM输出脚重映射到某个IO脚时,需设置重映射并且使能AFIO时钟

        4、时基单元初始化,配置ARR,PSC

        5、输出比较OCx初始化

        6、使能预装载寄存器

        7、使能定时器

        8、不断改变比较值CCRx(CCRx包含了装入当前捕获/比较x寄存器的值(预装载值)。),达到不同的占空比

以TIM2、TIM3为例输出变化的PWM波信号,输出到PB3、PB4、PB5引脚

PB3、PB4默认是JTAG功能,需使用引脚重映射关闭JTAG功能改为普通IO口

要在PB3、PB4、PB5输出PWM波需要使用TIM2_CH2的部分重映射1和TIM3_CH1和TIM3_CH2的部分重映射。

 部分重映射和完全重映射:所谓部分重映射就是部分管脚和默认的是一样的,而部分管脚是重新映射到其他管脚,而完全重 映射就是所有管脚都重新映射到其他管脚。通俗一点讲就是一个IO口有多个管脚,有的IO口是所有的管脚全部连接到一个外设上,有的IO口是一部分管脚接在一个外设上,另一部分管脚接在另一个外设上。

PWM占空比公式:  CCR / ARR + 1

PWM 频率: TIMxCLK  / (PSC + 1) / (ARR + 1)

PWM分辩率:1 / (ARR + 1)   越小越好

可通过 TIM_SetComparex(TIM2,uint16_t Compare);设置CCRx的值

//频率1000HZ,占空比50%的PWM GPIO_InitTypeDef GPIO_InitStruct; TIM_TimeBaseInitTypeDef TimeBaseInitStruct; TIM_OCInitTypeDef TIM_OCInitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3,ENABLE); //GPIO引脚重映射关闭JTAG功能和TIM功能 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE); //GPIO部分重映射 GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStruct); TimeBaseInitStruct.TIM_Period = 100 - 1; TimeBaseInitStruct.TIM_Prescaler = 720 - 1; TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2,&TimeBaseInitStruct); TIM_TimeBaseInit(TIM3,&TimeBaseInitStruct); TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_Pulse = 50; //CCR的值 TIM_OC1Init(TIM3,&TIM_OCInitStruct); TIM_OC2Init(TIM3,&TIM_OCInitStruct); TIM_OC2Init(TIM2,&TIM_OCInitStruct); TIM_Cmd(TIM2,ENABLE); TIM_Cmd(TIM3,ENABLE); void setPWM_Duty(uint16_t compare) { TIM_SetCompare1(TIM2,compare); TIM_SetCompare1(TIM3,compare); } 6、通用定时器输入捕获初始化步骤

        1、使能定时器时钟和相关GPIO的时钟

        2、初始化GPIO输入输出模式

        3、初始化时基单元,设置ARR,PSC的值

        4、初始化输入捕获通道

        5、开启捕获中断

        6、NVIC优先级分组和NVIC初始化

        7、使能定时器

        8、编写定时中断函数

以TIM3为例进行初始化

GPIO_InitTypeDef GPIO_InitStruct; TIM_TimeBaseInitTypeDef TimeBaseInitStruct; TIM_ICInitTypeDef TIM_ICInitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStruct); TimeBaseInitStruct.TIM_Period = 0xFFFF; //取最大值保证计数连续 TimeBaseInitStruct.TIM_Prescaler = 71; //sysclk = 72mhz 计数周期为1us TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3,&TimeBaseInitStruct); TIM_ICInitStruct.TIM_Channel = TIM_Channel_3; TIM_ICInitStruct.TIM_ICFilter = 0; //输入捕获筛选值 TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; //指定输入 TIM_ICInit(TIM3,&TIM_ICInitStruct); TIM_ITConfig(TIM3,TIM_IT_CC3,ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; NVIC_Init(&NVIC_InitStruct); TIM_Cmd(TIM3,ENABLE); 7、I2C总线初始化步骤

        1、开启  I2C时钟和I2C所在GPIO的时钟

        2、初始化I2C所在的GPIOB为规定的开漏复用输出模式

        3、I2C初始化,设置I2C通信的参数

        4、使能I2C

GPIO_InitTypeDef GPIO_InitStruct; I2C_InitTypeDef I2C_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //初始化GPIO PB6/SCL PB7/SDA GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStruct); //配置I2C为普通模式,主机 I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; I2C_InitStruct.I2C_OwnAddress1 = 0X45; //主机随意设置 I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; I2C_InitStruct.I2C_ClockSpeed = 4000; I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//应答地址,选择7位,从机模式下才有效 I2C_Cmd(I2C1,ENABLE); //自动应答ACK使能,初始化时不是能,后面可以函数调用。 I2C_AcknowledgeConfig(I2C1,ENABLE); 软件模拟I2C,by 江协科技 // @author 江协科技 /*引脚配置层*/ /** * 函 数:I2C写SCL引脚电平 * 参 数:BitValue 协议层传入的当前需要写入SCL的电平,范围0~1 * 返 回 值:无 * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SCL为低电平,当BitValue为1时,需要置SCL为高电平 */ void MyI2C_W_SCL(uint8_t BitValue) { GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue); //根据BitValue,设置SCL引脚的电平 Delay_us(10); //延时10us,防止时序频率超过要求 } /** * 函 数:I2C写SDA引脚电平 * 参 数:BitValue 协议层传入的当前需要写入SDA的电平,范围0~0xFF * 返 回 值:无 * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SDA为低电平,当BitValue非0时,需要置SDA为高电平 */ void MyI2C_W_SDA(uint8_t BitValue) { GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue); //根据BitValue,设置SDA引脚的电平,BitValue要实现非0即1的特性 Delay_us(10); //延时10us,防止时序频率超过要求 } /** * 函 数:I2C读SDA引脚电平 * 参 数:无 * 返 回 值:协议层需要得到的当前SDA的电平,范围0~1 * 注意事项:此函数需要用户实现内容,当前SDA为低电平时,返回0,当前SDA为高电平时,返回1 */ uint8_t MyI2C_R_SDA(void) { uint8_t BitValue; BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11); //读取SDA电平 Delay_us(10); //延时10us,防止时序频率超过要求 return BitValue; //返回SDA电平 } /** * 函 数:I2C初始化 * 参 数:无 * 返 回 值:无 * 注意事项:此函数需要用户实现内容,实现SCL和SDA引脚的初始化 */ void MyI2C_Init(void) { /*开启时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟 /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB10和PB11引脚初始化为开漏输出 /*设置默认电平*/ GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11); //设置PB10和PB11引脚初始化后默认为高电平(释放总线状态) } /*协议层*/ /** * 函 数:I2C起始 * 参 数:无 * 返 回 值:无 */ void MyI2C_Start(void) { MyI2C_W_SDA(1); //释放SDA,确保SDA为高电平 MyI2C_W_SCL(1); //释放SCL,确保SCL为高电平 MyI2C_W_SDA(0); //在SCL高电平期间,拉低SDA,产生起始信号 MyI2C_W_SCL(0); //起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接 } /** * 函 数:I2C终止 * 参 数:无 * 返 回 值:无 */ void MyI2C_Stop(void) { MyI2C_W_SDA(0); //拉低SDA,确保SDA为低电平 MyI2C_W_SCL(1); //释放SCL,使SCL呈现高电平 MyI2C_W_SDA(1); //在SCL高电平期间,释放SDA,产生终止信号 } /** * 函 数:I2C发送一个字节 * 参 数:Byte 要发送的一个字节数据,范围:0x00~0xFF * 返 回 值:无 */ void MyI2C_SendByte(uint8_t Byte) { uint8_t i; for (i = 0; i < 8; i ++) //循环8次,主机依次发送数据的每一位 { MyI2C_W_SDA(Byte & (0x80 >> i)); //使用掩码的方式取出Byte的指定一位数据并写入到SDA线 MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间读取SDA MyI2C_W_SCL(0); //拉低SCL,主机开始发送下一位数据 } } /** * 函 数:I2C接收一个字节 * 参 数:无 * 返 回 值:接收到的一个字节数据,范围:0x00~0xFF */ uint8_t MyI2C_ReceiveByte(void) { uint8_t i, Byte = 0x00; //定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到 MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送 for (i = 0; i < 8; i ++) //循环8次,主机依次接收数据的每一位 { MyI2C_W_SCL(1); //释放SCL,主机机在SCL高电平期间读取SDA if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);} //读取SDA数据,并存储到Byte变量 //当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0 MyI2C_W_SCL(0); //拉低SCL,从机在SCL低电平期间写入SDA } return Byte; //返回接收到的一个字节数据 } /** * 函 数:I2C发送应答位 * 参 数:Byte 要发送的应答位,范围:0~1,0表示应答,1表示非应答 * 返 回 值:无 */ void MyI2C_SendAck(uint8_t AckBit) { MyI2C_W_SDA(AckBit); //主机把应答位数据放到SDA线 MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间,读取应答位 MyI2C_W_SCL(0); //拉低SCL,开始下一个时序模块 } /** * 函 数:I2C接收应答位 * 参 数:无 * 返 回 值:接收到的应答位,范围:0~1,0表示应答,1表示非应答 */ uint8_t MyI2C_ReceiveAck(void) { uint8_t AckBit; //定义应答位变量 MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送 MyI2C_W_SCL(1); //释放SCL,主机机在SCL高电平期间读取SDA AckBit = MyI2C_R_SDA(); //将应答位存储到变量里 MyI2C_W_SCL(0); //拉低SCL,开始下一个时序模块 return AckBit; //返回定义应答位变量 } 8、DMA数据搬运初始化 MyDMA_Size = Size; //将Size写入到全局变量,记住参数Size /*开启时钟*/ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //开启DMA的时钟 /*DMA初始化*/ DMA_InitTypeDef DMA_InitStructure; //定义结构体变量 DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA; //外设基地址,给定形参AddrA DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度,选择字节 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设地址自增,选择使能 DMA_InitStructure.DMA_MemoryBaseAddr = AddrB; //存储器基地址,给定形参AddrB DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据宽度,选择字节 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址自增,选择使能 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,选择由外设到存储器 DMA_InitStructure.DMA_BufferSize = Size; //转运的数据大小(转运次数) DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //模式,选择正常模式 DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; //存储器到存储器,选择使能 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级,选择中等 DMA_Init(DMA1_Channel1, &DMA_InitStructure); //将结构体变量交给DMA_Init,配置DMA1的通道1 /*DMA使能*/ DMA_Cmd(DMA1_Channel1, DISABLE); //这里先不给使能,初始化后不会立刻工作,等后续调用Transfer后,再开始 //以下为搬运时配置 DMA_Cmd(DMA1_Channel1, DISABLE); //DMA失能,在写入传输计数器之前,需要DMA暂停工作 DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size); //写入传输计数器,指定将要转运的次数 DMA_Cmd(DMA1_Channel1, ENABLE); //DMA使能,开始工作 while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); //等待DMA工作完成 DMA_ClearFlag(DMA1_FLAG_TC1); //清除工作完成标志位 9、AD单通道初始化 void AD_Init(void) { /*开启时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 /*设置ADC时钟*/ RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为模拟输入 /*规则组通道配置*/ ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0 /*ADC初始化*/ ADC_InitTypeDef ADC_InitStructure; //定义结构体变量 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //连续转换,失能,每转换一次规则组序列后停止 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式,失能,只转换规则组的序列1这一个位置 ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1 ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1 /*ADC使能*/ ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行 /*ADC校准*/ ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准 while (ADC_GetResetCalibrationStatus(ADC1) == SET); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1) == SET); } /** * 函 数:获取AD转换的值 * 参 数:无 * 返 回 值:AD转换的值,范围:0~4095 */ uint16_t AD_GetValue(void) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次 while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束 return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果 } 10、AD多通道初始化 void AD_Init(void) { /*开启时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 /*设置ADC时钟*/ RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0、PA1、PA2和PA3引脚初始化为模拟输入 /*不在此处配置规则组序列,而是在每次AD转换前配置,这样可以灵活更改AD转换的通道*/ /*ADC初始化*/ ADC_InitTypeDef ADC_InitStructure; //定义结构体变量 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //连续转换,失能,每转换一次规则组序列后停止 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式,失能,只转换规则组的序列1这一个位置 ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1 ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1 /*ADC使能*/ ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行 /*ADC校准*/ ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准 while (ADC_GetResetCalibrationStatus(ADC1) == SET); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1) == SET); } /** * 函 数:获取AD转换的值 * 参 数:ADC_Channel 指定AD转换的通道,范围:ADC_Channel_x,其中x可以是0/1/2/3 * 返 回 值:AD转换的值,范围:0~4095 */ uint16_t AD_GetValue(uint8_t ADC_Channel) { ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); //在每次转换前,根据函数形参灵活更改规则组的通道1 ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次 while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束 return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果 }

标签:

STM32各外设初始化步骤由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“STM32各外设初始化步骤