当前位置:   article > 正文

STM32各外设初始化步骤_stm32初始化

stm32初始化

1、GPIO初始化步骤

        1、使能GPIO时钟

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

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

  1. GPIO_InitTypeDef GPIO_InitStruct;
  2. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  3. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  4. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
  5. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
  6. GPIO_Init(GPIOA,&GPIO_InitStruct);

2、EXTI的初始化步骤

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

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

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

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

        5、初始化EXTI

  1. GPIO_InitTypeDef GPIO_InitStruct;
  2. EXTI_InitTypeDef EXTI_InitStruct;
  3. NVIC_InitTypeDef NVIC_InitStruct;
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
  6. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  7. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
  8. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
  9. GPIO_Init(GPIOA,&GPIO_InitStruct);
  10. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_Pin_1);
  11. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  12. NVIC_InitStruct.NVIC_IRQChannel = EXTI1_IRQn;
  13. NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  14. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
  15. NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
  16. NVIC_Init(&NVIC_InitStruct);
  17. EXTI_InitStruct.EXTI_Line = EXTI_Line1;
  18. EXTI_InitStruct.EXTI_LineCmd = ENABLE;
  19. EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
  20. EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
  21. EXTI_Init(&EXTI_InitStruct);

3、USART的初始化步骤

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

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

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

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

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

        6、使能USARTx

  1. GPIO_InitTypeDef GPIO_InitStruct;
  2. USART_InitTypeDef USART_InitStruct;
  3. NVIC_InitTypeDef NVIC_InitStruct;
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
  6. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
  7. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
  8. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  9. GPIO_Init(GPIOA,&GPIO_InitStruct);
  10. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  11. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
  12. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  13. GPIO_Init(GPIOA,&GPIO_InitStruct);
  14. USART_InitStruct.USART_BaudRate = 115200;
  15. USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  16. USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
  17. USART_InitStruct.USART_Parity = USART_Parity_No;
  18. USART_InitStruct.USART_StopBits = USART_StopBits_1;
  19. USART_InitStruct.USART_WordLength = USART_WordLength_8b;
  20. USART_Init(USART1,&USART_InitStruct);
  21. USART_Cmd(USART1,ENABLE);
  22. USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //中断接收
  23. NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
  24. NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  25. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
  26. NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
  27. NVIC_Init(&NVIC_InitStruct);
  28. void USART1_IRQHandler(void)
  29. {
  30. //中断处理函数
  31. }

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。

  1. //以100ms为例配置TIM定时中断
  2. TIM_TimeBaseInitTypeDef TimeBaseInitStruct;
  3. NVIC_InitTypeDef NVIC_InitStruct;
  4. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
  5. TimeBaseInitStruct.TIM_Period = 999 + 1; //自动重装值
  6. TimeBaseInitStruct.TIM_Prescaler = 7199 + 1; //预分频值
  7. TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分割
  8. TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
  9. // TimeBaseInitStruct.TIM_RepetitionCounter = ; 重复计数值 pwm模式使用
  10. TIM_TimeBaseInit(TIM3,&TimeBaseInitStruct);
  11. TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除标志位,防止从1开始计数
  12. TIM_ITConfig(TIM3,ENABLE); //使能定时中断
  13. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分钟
  14. NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
  15. NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  16. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
  17. NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
  18. NVIC_Init(&NVIC_InitStruct);
  19. TIM_Cmd(TIM3,ENABLE);
  20. void TIM3_IRQHandler(void)
  21. {
  22. if(TIM_GetFlagStatus(TIM3,TIM_IT_Update) != RESET) //判断更新中断是否发生
  23. {
  24. //业务代码
  25. TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除标志位
  26. }
  27. }

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的值

  1. //频率1000HZ,占空比50%的PWM
  2. GPIO_InitTypeDef GPIO_InitStruct;
  3. TIM_TimeBaseInitTypeDef TimeBaseInitStruct;
  4. TIM_OCInitTypeDef TIM_OCInitStruct;
  5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  6. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
  7. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3,ENABLE);
  8. //GPIO引脚重映射关闭JTAG功能和TIM功能
  9. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
  10. GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE); //GPIO部分重映射
  11. GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);
  12. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
  13. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5
  14. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  15. GPIO_Init(GPIOB,&GPIO_InitStruct);
  16. TimeBaseInitStruct.TIM_Period = 100 - 1;
  17. TimeBaseInitStruct.TIM_Prescaler = 720 - 1;
  18. TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
  19. TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
  20. TIM_TimeBaseInit(TIM2,&TimeBaseInitStruct);
  21. TIM_TimeBaseInit(TIM3,&TimeBaseInitStruct);
  22. TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
  23. TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
  24. TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
  25. TIM_OCInitStruct.TIM_Pulse = 50; //CCR的值
  26. TIM_OC1Init(TIM3,&TIM_OCInitStruct);
  27. TIM_OC2Init(TIM3,&TIM_OCInitStruct);
  28. TIM_OC2Init(TIM2,&TIM_OCInitStruct);
  29. TIM_Cmd(TIM2,ENABLE);
  30. TIM_Cmd(TIM3,ENABLE);
  31. void setPWM_Duty(uint16_t compare)
  32. {
  33. TIM_SetCompare1(TIM2,compare);
  34. TIM_SetCompare1(TIM3,compare);
  35. }

6、通用定时器输入捕获初始化步骤

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

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

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

        4、初始化输入捕获通道

        5、开启捕获中断

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

        7、使能定时器

        8、编写定时中断函数

以TIM3为例进行初始化

  1. GPIO_InitTypeDef GPIO_InitStruct;
  2. TIM_TimeBaseInitTypeDef TimeBaseInitStruct;
  3. TIM_ICInitTypeDef TIM_ICInitStruct;
  4. NVIC_InitTypeDef NVIC_InitStruct;
  5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  6. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
  7. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  8. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
  9. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  10. GPIO_Init(GPIOB,&GPIO_InitStruct);
  11. TimeBaseInitStruct.TIM_Period = 0xFFFF; //取最大值保证计数连续
  12. TimeBaseInitStruct.TIM_Prescaler = 71; //sysclk = 72mhz 计数周期为1us
  13. TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
  14. TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
  15. TIM_TimeBaseInit(TIM3,&TimeBaseInitStruct);
  16. TIM_ICInitStruct.TIM_Channel = TIM_Channel_3;
  17. TIM_ICInitStruct.TIM_ICFilter = 0; //输入捕获筛选值
  18. TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
  19. TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  20. TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; //指定输入
  21. TIM_ICInit(TIM3,&TIM_ICInitStruct);
  22. TIM_ITConfig(TIM3,TIM_IT_CC3,ENABLE);
  23. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  24. NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
  25. NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  26. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
  27. NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
  28. NVIC_Init(&NVIC_InitStruct);
  29. TIM_Cmd(TIM3,ENABLE);

7、I2C总线初始化步骤

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

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

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

        4、使能I2C

  1. GPIO_InitTypeDef GPIO_InitStruct;
  2. I2C_InitTypeDef I2C_InitStruct;
  3. RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  5. //初始化GPIO PB6/SCL PB7/SDA
  6. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  7. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
  8. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  9. GPIO_Init(GPIOB,&GPIO_InitStruct);
  10. //配置I2C为普通模式,主机
  11. I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
  12. I2C_InitStruct.I2C_OwnAddress1 = 0X45; //主机随意设置
  13. I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
  14. I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
  15. I2C_InitStruct.I2C_ClockSpeed = 4000;
  16. I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//应答地址,选择7位,从机模式下才有效
  17. I2C_Cmd(I2C1,ENABLE);
  18. //自动应答ACK使能,初始化时不是能,后面可以函数调用。
  19. I2C_AcknowledgeConfig(I2C1,ENABLE);

软件模拟I2C,by 江协科技

  1. // @author 江协科技
  2. /*引脚配置层*/
  3. /**
  4. * 函 数:I2C写SCL引脚电平
  5. * 参 数:BitValue 协议层传入的当前需要写入SCL的电平,范围0~1
  6. * 返 回 值:无
  7. * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SCL为低电平,当BitValue为1时,需要置SCL为高电平
  8. */
  9. void MyI2C_W_SCL(uint8_t BitValue)
  10. {
  11. GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue); //根据BitValue,设置SCL引脚的电平
  12. Delay_us(10); //延时10us,防止时序频率超过要求
  13. }
  14. /**
  15. * 函 数:I2C写SDA引脚电平
  16. * 参 数:BitValue 协议层传入的当前需要写入SDA的电平,范围0~0xFF
  17. * 返 回 值:无
  18. * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SDA为低电平,当BitValue非0时,需要置SDA为高电平
  19. */
  20. void MyI2C_W_SDA(uint8_t BitValue)
  21. {
  22. GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue); //根据BitValue,设置SDA引脚的电平,BitValue要实现非0即1的特性
  23. Delay_us(10); //延时10us,防止时序频率超过要求
  24. }
  25. /**
  26. * 函 数:I2C读SDA引脚电平
  27. * 参 数:无
  28. * 返 回 值:协议层需要得到的当前SDA的电平,范围0~1
  29. * 注意事项:此函数需要用户实现内容,当前SDA为低电平时,返回0,当前SDA为高电平时,返回1
  30. */
  31. uint8_t MyI2C_R_SDA(void)
  32. {
  33. uint8_t BitValue;
  34. BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11); //读取SDA电平
  35. Delay_us(10); //延时10us,防止时序频率超过要求
  36. return BitValue; //返回SDA电平
  37. }
  38. /**
  39. * 函 数:I2C初始化
  40. * 参 数:无
  41. * 返 回 值:无
  42. * 注意事项:此函数需要用户实现内容,实现SCL和SDA引脚的初始化
  43. */
  44. void MyI2C_Init(void)
  45. {
  46. /*开启时钟*/
  47. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
  48. /*GPIO初始化*/
  49. GPIO_InitTypeDef GPIO_InitStructure;
  50. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
  51. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
  52. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  53. GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB10和PB11引脚初始化为开漏输出
  54. /*设置默认电平*/
  55. GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11); //设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
  56. }
  57. /*协议层*/
  58. /**
  59. * 函 数:I2C起始
  60. * 参 数:无
  61. * 返 回 值:无
  62. */
  63. void MyI2C_Start(void)
  64. {
  65. MyI2C_W_SDA(1); //释放SDA,确保SDA为高电平
  66. MyI2C_W_SCL(1); //释放SCL,确保SCL为高电平
  67. MyI2C_W_SDA(0); //在SCL高电平期间,拉低SDA,产生起始信号
  68. MyI2C_W_SCL(0); //起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接
  69. }
  70. /**
  71. * 函 数:I2C终止
  72. * 参 数:无
  73. * 返 回 值:无
  74. */
  75. void MyI2C_Stop(void)
  76. {
  77. MyI2C_W_SDA(0); //拉低SDA,确保SDA为低电平
  78. MyI2C_W_SCL(1); //释放SCL,使SCL呈现高电平
  79. MyI2C_W_SDA(1); //在SCL高电平期间,释放SDA,产生终止信号
  80. }
  81. /**
  82. * 函 数:I2C发送一个字节
  83. * 参 数:Byte 要发送的一个字节数据,范围:0x00~0xFF
  84. * 返 回 值:无
  85. */
  86. void MyI2C_SendByte(uint8_t Byte)
  87. {
  88. uint8_t i;
  89. for (i = 0; i < 8; i ++) //循环8次,主机依次发送数据的每一位
  90. {
  91. MyI2C_W_SDA(Byte & (0x80 >> i)); //使用掩码的方式取出Byte的指定一位数据并写入到SDA线
  92. MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间读取SDA
  93. MyI2C_W_SCL(0); //拉低SCL,主机开始发送下一位数据
  94. }
  95. }
  96. /**
  97. * 函 数:I2C接收一个字节
  98. * 参 数:无
  99. * 返 回 值:接收到的一个字节数据,范围:0x00~0xFF
  100. */
  101. uint8_t MyI2C_ReceiveByte(void)
  102. {
  103. uint8_t i, Byte = 0x00; //定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到
  104. MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送
  105. for (i = 0; i < 8; i ++) //循环8次,主机依次接收数据的每一位
  106. {
  107. MyI2C_W_SCL(1); //释放SCL,主机机在SCL高电平期间读取SDA
  108. if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);} //读取SDA数据,并存储到Byte变量
  109. //当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0
  110. MyI2C_W_SCL(0); //拉低SCL,从机在SCL低电平期间写入SDA
  111. }
  112. return Byte; //返回接收到的一个字节数据
  113. }
  114. /**
  115. * 函 数:I2C发送应答位
  116. * 参 数:Byte 要发送的应答位,范围:0~1,0表示应答,1表示非应答
  117. * 返 回 值:无
  118. */
  119. void MyI2C_SendAck(uint8_t AckBit)
  120. {
  121. MyI2C_W_SDA(AckBit); //主机把应答位数据放到SDA线
  122. MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间,读取应答位
  123. MyI2C_W_SCL(0); //拉低SCL,开始下一个时序模块
  124. }
  125. /**
  126. * 函 数:I2C接收应答位
  127. * 参 数:无
  128. * 返 回 值:接收到的应答位,范围:0~1,0表示应答,1表示非应答
  129. */
  130. uint8_t MyI2C_ReceiveAck(void)
  131. {
  132. uint8_t AckBit; //定义应答位变量
  133. MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送
  134. MyI2C_W_SCL(1); //释放SCL,主机机在SCL高电平期间读取SDA
  135. AckBit = MyI2C_R_SDA(); //将应答位存储到变量里
  136. MyI2C_W_SCL(0); //拉低SCL,开始下一个时序模块
  137. return AckBit; //返回定义应答位变量
  138. }

8、DMA数据搬运初始化

  1. MyDMA_Size = Size; //将Size写入到全局变量,记住参数Size
  2. /*开启时钟*/
  3. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //开启DMA的时钟
  4. /*DMA初始化*/
  5. DMA_InitTypeDef DMA_InitStructure; //定义结构体变量
  6. DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA; //外设基地址,给定形参AddrA
  7. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度,选择字节
  8. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设地址自增,选择使能
  9. DMA_InitStructure.DMA_MemoryBaseAddr = AddrB; //存储器基地址,给定形参AddrB
  10. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据宽度,选择字节
  11. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址自增,选择使能
  12. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,选择由外设到存储器
  13. DMA_InitStructure.DMA_BufferSize = Size; //转运的数据大小(转运次数)
  14. DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //模式,选择正常模式
  15. DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; //存储器到存储器,选择使能
  16. DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级,选择中等
  17. DMA_Init(DMA1_Channel1, &DMA_InitStructure); //将结构体变量交给DMA_Init,配置DMA1的通道1
  18. /*DMA使能*/
  19. DMA_Cmd(DMA1_Channel1, DISABLE); //这里先不给使能,初始化后不会立刻工作,等后续调用Transfer后,再开始
  20. //以下为搬运时配置
  21. DMA_Cmd(DMA1_Channel1, DISABLE); //DMA失能,在写入传输计数器之前,需要DMA暂停工作
  22. DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size); //写入传输计数器,指定将要转运的次数
  23. DMA_Cmd(DMA1_Channel1, ENABLE); //DMA使能,开始工作
  24. while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); //等待DMA工作完成
  25. DMA_ClearFlag(DMA1_FLAG_TC1); //清除工作完成标志位

9、AD单通道初始化

  1. void AD_Init(void)
  2. {
  3. /*开启时钟*/
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟
  5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
  6. /*设置ADC时钟*/
  7. RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz
  8. /*GPIO初始化*/
  9. GPIO_InitTypeDef GPIO_InitStructure;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  11. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  12. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13. GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为模拟输入
  14. /*规则组通道配置*/
  15. ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0
  16. /*ADC初始化*/
  17. ADC_InitTypeDef ADC_InitStructure; //定义结构体变量
  18. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1
  19. ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐
  20. ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
  21. ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //连续转换,失能,每转换一次规则组序列后停止
  22. ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式,失能,只转换规则组的序列1这一个位置
  23. ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
  24. ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1
  25. /*ADC使能*/
  26. ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行
  27. /*ADC校准*/
  28. ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准
  29. while (ADC_GetResetCalibrationStatus(ADC1) == SET);
  30. ADC_StartCalibration(ADC1);
  31. while (ADC_GetCalibrationStatus(ADC1) == SET);
  32. }
  33. /**
  34. * 函 数:获取AD转换的值
  35. * 参 数:无
  36. * 返 回 值:AD转换的值,范围:0~4095
  37. */
  38. uint16_t AD_GetValue(void)
  39. {
  40. ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次
  41. while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
  42. return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果
  43. }

10、AD多通道初始化

  1. void AD_Init(void)
  2. {
  3. /*开启时钟*/
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟
  5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
  6. /*设置ADC时钟*/
  7. RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz
  8. /*GPIO初始化*/
  9. GPIO_InitTypeDef GPIO_InitStructure;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  11. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
  12. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13. GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0、PA1、PA2和PA3引脚初始化为模拟输入
  14. /*不在此处配置规则组序列,而是在每次AD转换前配置,这样可以灵活更改AD转换的通道*/
  15. /*ADC初始化*/
  16. ADC_InitTypeDef ADC_InitStructure; //定义结构体变量
  17. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1
  18. ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐
  19. ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
  20. ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //连续转换,失能,每转换一次规则组序列后停止
  21. ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式,失能,只转换规则组的序列1这一个位置
  22. ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
  23. ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1
  24. /*ADC使能*/
  25. ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行
  26. /*ADC校准*/
  27. ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准
  28. while (ADC_GetResetCalibrationStatus(ADC1) == SET);
  29. ADC_StartCalibration(ADC1);
  30. while (ADC_GetCalibrationStatus(ADC1) == SET);
  31. }
  32. /**
  33. * 函 数:获取AD转换的值
  34. * 参 数:ADC_Channel 指定AD转换的通道,范围:ADC_Channel_x,其中x可以是0/1/2/3
  35. * 返 回 值:AD转换的值,范围:0~4095
  36. */
  37. uint16_t AD_GetValue(uint8_t ADC_Channel)
  38. {
  39. ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); //在每次转换前,根据函数形参灵活更改规则组的通道1
  40. ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次
  41. while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
  42. return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果
  43. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/568162
推荐阅读
相关标签
  

闽ICP备14008679号