当前位置: 首页 > article >正文

25/1/16 嵌入式笔记 STM32F108

输入捕获

TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_TimeBaseStruct.TIM_Period = 0xFFFF;  // 自动重装载值
TIM_TimeBaseStruct.TIM_Prescaler = 71;  // 预分频值
TIM_TimeBaseStruct.TIM_ClockDivision = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;  // 向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);
  1. 频率计算

    • 通过两次捕获的计数器值之差,结合定时器的时钟频率,可以计算出信号的频率或周期。

输入捕获的配置步骤

使能定时器时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  // 使能TIM2时钟

配置定时器基本参数

TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_TimeBaseStruct.TIM_Period = 0xFFFF;  // 自动重装载值
TIM_TimeBaseStruct.TIM_Prescaler = 71;  // 预分频值
TIM_TimeBaseStruct.TIM_ClockDivision = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;  // 向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);

配置输入捕获模式

TIM_ICInitTypeDef TIM_ICStruct;
TIM_ICStruct.TIM_Channel = TIM_Channel_1;  // 选择通道1
TIM_ICStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;  // 捕获上升沿
TIM_ICStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;  // 直接输入
TIM_ICStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;  // 不分频
TIM_ICStruct.TIM_ICFilter = 0x0;  // 无滤波
TIM_ICInit(TIM2, &TIM_ICStruct);

使能捕获中断

TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);  // 使能捕获中断
NVIC_EnableIRQ(TIM2_IRQn);  // 使能TIM2中断

使能定时器

TIM_Cmd(TIM2, ENABLE);  // 使能TIM2

完整代码

#include "stm32f10x.h"

volatile uint16_t CaptureValue1 = 0;  // 第一次捕获值
volatile uint16_t CaptureValue2 = 0;  // 第二次捕获值
volatile uint16_t Period = 0;  // 信号周期
volatile uint32_t Frequency = 0;  // 信号频率

void TIM2_IC_Init(void) {
    // 使能TIM2时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    // 配置定时器基本参数
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
    TIM_TimeBaseStruct.TIM_Period = 0xFFFF;  // 自动重装载值
    TIM_TimeBaseStruct.TIM_Prescaler = 71;  // 预分频值
    TIM_TimeBaseStruct.TIM_ClockDivision = 0;
    TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;  // 向上计数模式
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);

    // 配置输入捕获模式
    TIM_ICInitTypeDef TIM_ICStruct;
    TIM_ICStruct.TIM_Channel = TIM_Channel_1;  // 选择通道1
    TIM_ICStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;  // 捕获上升沿
    TIM_ICStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;  // 直接输入
    TIM_ICStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;  // 不分频
    TIM_ICStruct.TIM_ICFilter = 0x0;  // 无滤波
    TIM_ICInit(TIM2, &TIM_ICStruct);

    // 使能捕获中断
    TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);  // 使能捕获中断
    NVIC_EnableIRQ(TIM2_IRQn);  // 使能TIM2中断

    // 使能定时器
    TIM_Cmd(TIM2, ENABLE);
}

void TIM2_IRQHandler(void) {
    if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) {
        if (CaptureValue1 == 0) {
            // 第一次捕获
            CaptureValue1 = TIM_GetCapture1(TIM2);
        } else {
            // 第二次捕获
            CaptureValue2 = TIM_GetCapture1(TIM2);

            // 计算周期
            if (CaptureValue2 > CaptureValue1) {
                Period = CaptureValue2 - CaptureValue1;
            } else {
                Period = (0xFFFF - CaptureValue1) + CaptureValue2;
            }

            // 计算频率
            Frequency = 1000000 / Period;  // 假设定时器时钟为1MHz

            // 重置捕获值
            CaptureValue1 = 0;
            CaptureValue2 = 0;
        }

        // 清除中断标志
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
    }
}

int main(void) {
    // 初始化输入捕获
    TIM2_IC_Init();

    while (1) {
        // 主循环
    }
}

编码器接口

1. 编码器接口的基本原理

  1. 编码器信号

    • 旋转编码器通常输出两路正交信号(A相和B相),用于表示旋转方向和速度。

  2. 计数器

    • 编码器接口通过捕获A相和B相的边沿信号,驱动定时器的计数器(CNT)递增或递减。

  3. 速度计算

    • 通过读取计数器的值,可以计算出编码器的旋转速度。

速度计算

  • 编码器分辨率:假设编码器的分辨率为1000脉冲/转。

  • 速度计算

    • 速度 = 编码器计数器值 / 编码器分辨率。

编码器接口的配置步骤

使能定时器时钟

  • STM32的外设(如定时器)默认是关闭时钟的,以节省功耗。

  • 使用外设前,必须使能其时钟,否则外设无法工作。

  • 这里使能了TIM2的时钟,因为我们将使用TIM2的编码器接口功能。

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  // 使能TIM2时钟

配置定时器基本参数

  • 自动重装载值(TIM_Period)

    • 设置定时器计数器的最大值。这里设置为 0xFFFF(16位定时器的最大值),表示计数器从0计数到65535后溢出。

    • 编码器模式下,计数器会根据编码器的脉冲信号递增或递减,因此需要足够大的计数范围。

  • 预分频器(TIM_Prescaler)

    • 用于分频定时器的时钟频率。这里设置为0,表示不分频,定时器直接使用输入时钟频率。

    • 如果编码器脉冲频率较高,可以适当增加预分频值以降低计数器频率。

  • 时钟分频(TIM_ClockDivision)

    • 用于分频定时器的输入时钟。这里设置为0,表示不进行额外的时钟分频。

  • 计数模式(TIM_CounterMode)

    • 设置计数器的计数模式。编码器模式下,计数模式通常设置为向上计数(TIM_CounterMode_Up),但实际计数方向由编码器信号决定。

TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_TimeBaseStruct.TIM_Period = 0xFFFF;  // 自动重装载值
TIM_TimeBaseStruct.TIM_Prescaler = 0;  // 不分频
TIM_TimeBaseStruct.TIM_ClockDivision = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;  // 向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);

配置编码器接口模式

  • 编码器模式(TIM_EncoderMode_TI12)

    • 设置定时器为编码器模式,使用TIM2的通道1和通道2(TI1和TI2)作为编码器的输入信号。

    • 编码器模式会根据A相和B相信号的边沿变化来驱动计数器递增或递减。

  • 输入捕获极性(TIM_ICPolarity_Rising)

    • 设置编码器信号的捕获边沿。这里设置为上升沿触发,表示在A相和B相信号的上升沿时捕获计数器值。

TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);

配置输入捕获通道

  • 通道选择(TIM_Channel)

    • 选择定时器的通道1和通道2作为编码器的输入信号。

  • 捕获极性(TIM_ICPolarity)

    • 设置捕获信号的边沿。这里设置为上升沿触发。

  • 输入选择(TIM_ICSelection)

    • 设置输入信号的来源。这里设置为直接输入(TIM_ICSelection_DirectTI),表示直接使用TIM2的通道1和通道2作为输入。

  • 输入分频(TIM_ICPrescaler)

    • 设置输入信号的分频。这里设置为不分频(TIM_ICPSC_DIV1),表示每个边沿都触发捕获。

  • 输入滤波(TIM_ICFilter)

    • 设置输入信号的滤波。这里设置为无滤波(0x0),表示不对输入信号进行滤波。

TIM_ICInitTypeDef TIM_ICStruct;
TIM_ICStruct.TIM_Channel = TIM_Channel_1;  // 选择通道1
TIM_ICStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;  // 捕获上升沿
TIM_ICStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;  // 直接输入
TIM_ICStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;  // 不分频
TIM_ICStruct.TIM_ICFilter = 0x0;  // 无滤波
TIM_ICInit(TIM2, &TIM_ICStruct);

TIM_ICStruct.TIM_Channel = TIM_Channel_2;  // 选择通道2
TIM_ICInit(TIM2, &TIM_ICStruct);

 使能定时器

  • 使能定时器后,定时器开始工作,计数器会根据编码器信号的变化递增或递减。

  • 如果不使能定时器,编码器接口将无法工作。

TIM_Cmd(TIM2, ENABLE);  // 使能TIM2
完整代码
#include "stm32f10x.h"

volatile int16_t EncoderCount = 0;  // 编码器计数器值

void TIM2_Encoder_Init(void) {
    // 使能TIM2时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    // 配置定时器基本参数
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
    TIM_TimeBaseStruct.TIM_Period = 0xFFFF;  // 自动重装载值
    TIM_TimeBaseStruct.TIM_Prescaler = 0;  // 不分频
    TIM_TimeBaseStruct.TIM_ClockDivision = 0;
    TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;  // 向上计数模式
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);

    // 配置编码器接口模式
    TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);

    // 配置输入捕获通道
    TIM_ICInitTypeDef TIM_ICStruct;
    TIM_ICStruct.TIM_Channel = TIM_Channel_1;  // 选择通道1
    TIM_ICStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;  // 捕获上升沿
    TIM_ICStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;  // 直接输入
    TIM_ICStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;  // 不分频
    TIM_ICStruct.TIM_ICFilter = 0x0;  // 无滤波
    TIM_ICInit(TIM2, &TIM_ICStruct);

    TIM_ICStruct.TIM_Channel = TIM_Channel_2;  // 选择通道2
    TIM_ICInit(TIM2, &TIM_ICStruct);

    // 使能定时器
    TIM_Cmd(TIM2, ENABLE);
}

int main(void) {
    // 初始化编码器接口
    TIM2_Encoder_Init();

    while (1) {
        // 读取编码器计数器值
        EncoderCount = TIM_GetCounter(TIM2);

        // 主循环
    }
}

模数转换器

ADC基本结构

ADC(Analog-to-Digital Converter,模数转换器)用于将模拟信号转换为数字信号。STM32的ADC模块通常包括以下主要部分:

1.1 模拟看门狗(Analog Watchdog)
  • 作用:监控ADC转换结果,当转换结果超出设定的阈值范围时,触发中断或事件。

  • 应用场景:用于检测模拟信号是否在正常范围内。

1.2 中断输出控制
  • 作用:在ADC转换完成、模拟看门狗触发等事件发生时,产生中断信号。

  • 应用场景:用于通知CPU处理ADC转换结果。

1.3 CPU
  • 作用:处理ADC转换结果,执行相应的逻辑。

1.4 ADC转换器
  • 作用:将模拟信号转换为数字信号。

  • 分辨率:STM32的ADC通常支持12位分辨率,即转换结果为0到4095。

1.5 AD数据寄存器
  • 作用:存储ADC转换结果。

  • 规则组结果:存储规则组通道的转换结果。

  • 注入组结果:存储注入组通道的转换结果。

1.6 规则组(Regular Group)
  • 作用:用于常规的ADC转换,支持多个通道按顺序转换。

  • 特点:规则组转换结果存储在单个寄存器中。

1.7 注入组(Injected Group)
  • 作用:用于高优先级的ADC转换,支持多个通道按顺序转换。

  • 特点:注入组转换结果存储在多个寄存器中,优先级高于规则组。

1.8 温度传感器
  • 作用:内置温度传感器,用于测量芯片温度。

  • 特点:通常连接到ADC的某个通道。

1.9 VREFINT
  • 作用:内部参考电压,用于校准ADC转换结果。

  • 特点:通常连接到ADC的某个通道。

1.10 START
  • 作用:启动ADC转换。

  • 触发方式:可以通过软件或外部事件触发。

1.11 CLOCK
  • 作用:提供ADC转换的时钟信号。

  • 来源:通常由RCC(Reset and Clock Control)模块提供。

1.12 触发控制
  • 作用:控制ADC转换的触发方式。

  • 触发源:可以是定时器、外部信号等。

1.13 RCC
  • 作用:提供ADC模块的时钟信号。

  • 配置:通过RCC配置ADC的时钟频率。

1.14 开关控制
  • 作用:控制ADC模块的开启和关闭。

  • 应用场景:用于节省功耗。

#include "stm32f10x.h"  // 包含STM32F10x系列的头文件

void ADC_Init(void) {
    // 1. 使能GPIOA和ADC1的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);

    // 2. 配置GPIOA的引脚0为模拟输入模式
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;  // 选择引脚0
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;  // 模拟输入模式
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 3. 配置ADC1
    ADC_InitTypeDef ADC_InitStruct;
    ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;  // 独立模式
    ADC_InitStruct.ADC_ScanConvMode = DISABLE;  // 单通道模式
    ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;  // 单次转换模式
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  // 软件触发
    ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;  // 数据右对齐
    ADC_InitStruct.ADC_NbrOfChannel = 1;  // 1个通道
    ADC_Init(ADC1, &ADC_InitStruct);

    // 4. 配置ADC1的通道0(PA0)
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

    // 5. 使能ADC1
    ADC_Cmd(ADC1, ENABLE);

    // 6. 校准ADC1
    ADC_ResetCalibration(ADC1);  // 重置校准寄存器
    while (ADC_GetResetCalibrationStatus(ADC1));  // 等待重置完成
    ADC_StartCalibration(ADC1);  // 开始校准
    while (ADC_GetCalibrationStatus(ADC1));  // 等待校准完成
}

uint16_t ADC_Read(void) {
    // 1. 启动ADC转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);

    // 2. 等待转换完成
    while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));

    // 3. 读取转换结果
    return ADC_GetConversionValue(ADC1);
}

int main(void) {
    // 初始化ADC
    ADC_Init();

    while (1) {
        // 读取ADC值
        uint16_t adcValue = ADC_Read();

        // 处理ADC值(例如:打印到串口或控制LED)
        // ...
    }
}

直接存储器DMA

通信接口

USART协议


http://www.kler.cn/a/506813.html

相关文章:

  • redis(2:数据结构)
  • 港科夜闻 | 香港科大与微软亚洲研究院签署战略合作备忘录,推动医学健康教育及科研协作...
  • 以太网实战AD采集上传上位机——FPGA学习笔记27
  • 电商项目-基于ElasticSearch实现商品搜索功能(三)
  • 3.Qt Quick-QML地图引擎之v4.3版本(新增动态轨迹线/海图/天地图街道/天地图卫星)
  • 查看APK的公钥,MD5信息
  • C语言结构体漫谈:从平凡中见不平凡
  • 《基于深度学习的多色光度巡天项目天文目标检测框架》论文精读
  • 1 使用EMIO
  • 【Axure】配色库
  • 5、docker-compose和docker-harbor
  • 电池预测 | 第21讲 基于Gamma伽马模型结合EM算法和粒子滤波算法参数估计的锂电池剩余寿命预测
  • python中自动化playwright录制功能跳过繁琐的系统登录操作
  • Git在add的时候出现error: unable to index file 的问题,导致add失败的问题解决
  • 大数据就业前景及待遇如何?
  • 打造更安全的Linux系统:玩转PAM配置文件
  • 为Hugo/Hexo设计的在线Markdown编辑器
  • Flutter 多终端测试 自定义启动画面​​​​​​​ 更换小图标和应用名称
  • RK3568-Linux应用学习记录
  • 复用类(2):代理、结合使用组合和继承
  • 三数之和力扣--15
  • Unity3d 实时天气系统基于UniStorm插件和xx天气API实现(含源码)
  • 音视频文件提供流式传输之HTTP Live Streaming (HLS)
  • SUN的J2EE与微软的DNA
  • 【设计模式】6大设计原则和23种设计模式
  • 【Linux】10.Linux基础开发工具使用(3)