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%的PWMGPIO_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_5GPIO_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/SDAGPIO_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高电平期间读取SDAMyI2C_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高电平期间读取SDAif (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);} //读取SDA数据,并存储到Byte变量//当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0MyI2C_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高电平期间读取SDAAckBit = 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; //外设基地址,给定形参AddrADMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度,选择字节DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设地址自增,选择使能DMA_InitStructure.DMA_MemoryBaseAddr = AddrB; //存储器基地址,给定形参AddrBDMA_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; //模式,选择独立模式,即单独使用ADC1ADC_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的数,在非扫描模式下,只能是1ADC_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; //模式,选择独立模式,即单独使用ADC1ADC_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的数,在非扫描模式下,只能是1ADC_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); //在每次转换前,根据函数形参灵活更改规则组的通道1ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果
}