打印
[STM32F1]

stm32(F103c8t6)自学笔记

[复制链接]
楼主: t60yz
手机看帖
扫描二维码
随时随地手机跟帖
141
t60yz|  楼主 | 2023-11-22 11:46 | 只看该作者 |只看大图 回帖奖励 |倒序浏览

使用特权

评论回复
142
t60yz|  楼主 | 2023-11-22 11:46 | 只看该作者

使用特权

评论回复
143
t60yz|  楼主 | 2023-11-22 11:47 | 只看该作者
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Bianmaqi.h"
#include "Delay.h"
#include "timer2.h"

/***************************************************/延时函数
#include "Delay.h"
#include "stm32f10x.h"

/**
  * @brief  微秒级延时
  * @param  xus 延时时长,范围:0~233015
  * @retval 无
  */
void Delay_us(uint32_t xus)
{
        SysTick->LOAD = 72 * xus;                                //设置定时器重装值
        SysTick->VAL = 0x00;                                        //清空当前计数值
        SysTick->CTRL = 0x00000005;                                //设置时钟源为HCLK,启动定时器
        while(!(SysTick->CTRL & 0x00010000));        //等待计数到0
        SysTick->CTRL = 0x00000004;                                //关闭定时器
}

/**
  * @brief  毫秒级延时
  * @param  xms 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_ms(uint32_t xms)
{
        while(xms--)
        {
                Delay_us(1000);
        }
}

/**
  * @brief  秒级延时
  * @param  xs 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_s(uint32_t xs)
{
        while(xs--)
        {
                Delay_ms(1000);
        }
}

/***************************************************/编码器
#include "stm32f10x.h"                  // Device header
#include "Bianmaqi.h"

void Bianmaqi_init(void)
{
        //1**使能时钟
        RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM3,ENABLE);
        RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA,ENABLE);
       
        //2**定义GPIO
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6 |GPIO_Pin_7;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
       
        //3**初始化时基单元
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
        TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_Channel_1|TIM_Channel_2;
        TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CKD_DIV1;
        TIM_TimeBaseInitStruct.TIM_Period=65536-1;
        TIM_TimeBaseInitStruct.TIM_Prescaler=1-1;
        TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
        TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
       
        //4**初始化IC模块(部分)两个Pin口
        TIM_ICInitTypeDef TIM_ICInitStruct;
        TIM_ICStructInit(&TIM_ICInitStruct);
        TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
        TIM_ICInitStruct.TIM_ICFilter=0xF;
//        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_ICInitStruct.TIM_Channel=TIM_Channel_2;
        TIM_ICInitStruct.TIM_ICFilter=0xF;
//        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);
       
        //5**配置编码器
        TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Falling,TIM_ICPolarity_Rising);//控制极性
       
        //6.使能定时器TIM3
        TIM_Cmd(TIM3,ENABLE);
}

int16_t get_cnt(void)
{
        int16_t temp=0;
        temp=TIM_GetCounter(TIM3);
        TIM_SetCounter(TIM3,0);
        return temp;
}

/***************************************************/定时器TIM2
#include "stm32f10x.h"
#include "timer2.h"

extern int num;
void timer2_init(void)
{
        //**1.打开总的RCC,要配置GPIO从而传入外部时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
        //**2.配置定时器接入外部时钟 同时配置外部时钟输入的引脚
        TIM_InternalClockConfig(TIM2);//设置定时器2使用内部时钟,可不写,上电默认
       
        GPIO_InitTypeDef GPIO_InitStruct;
       
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOB,&GPIO_InitStruct);
       
        //TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//第二个设置分频,第三个设置触发方式,第四个设置采样频率(滤波器)
        //**3.配置时基单元
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
       
        TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
        TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上l计数
        TIM_TimeBaseInitStruct.TIM_Period=10000-1;//设置预装载值       //外部时钟的话用不了这么高的频率
        TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;//设置预分频值
//        TIM_TimeBaseInitStruct.TIM_Period=10-1;//设置预装载值
//        TIM_TimeBaseInitStruct.TIM_Prescaler=2-1;//设置预分频值
        TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
        TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除
        //**4.使能时基单元的中断
        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
        //**5.配置NVIC
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组
       
        NVIC_InitTypeDef NVIC_InitStruct;
        NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
        NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
        NVIC_Init(&NVIC_InitStruct);
        //**6.开始计数
        TIM_Cmd(TIM2,ENABLE);

}
/*
//配置中断函数
void TIM2_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
        {
                num++;
        }
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
*/

/***************************************************/主函数
int16_t speed=0;
int main(void)
{
        timer2_init();
        OLED_Init();
        Bianmaqi_init();
        OLED_ShowString(1,1,"Hello,my honey");
        while(1)
        {
                OLED_ShowSignedNum(2,1,speed,6);
        }
}

void TIM2_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
        {
                speed=get_cnt();
                Delay_ms (10);
        }
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

}

使用特权

评论回复
144
t60yz|  楼主 | 2023-11-22 11:59 | 只看该作者
七、ADC模数转换
1.结构原理
1.1 介绍

使用特权

评论回复
145
t60yz|  楼主 | 2023-11-22 11:59 | 只看该作者

使用特权

评论回复
146
t60yz|  楼主 | 2023-11-22 11:59 | 只看该作者
1.2 原理
采样、抽取、量化、编码

使用特权

评论回复
147
t60yz|  楼主 | 2023-11-22 12:00 | 只看该作者

使用特权

评论回复
148
t60yz|  楼主 | 2023-11-22 12:00 | 只看该作者
1.3 ADC结构框图

使用特权

评论回复
149
t60yz|  楼主 | 2023-11-22 12:01 | 只看该作者
1.4 stm32片上资源

使用特权

评论回复
150
t60yz|  楼主 | 2023-11-22 12:01 | 只看该作者
1.5 ADC工作的4种模式
1.5.1 单次转换,非扫描模式

使用特权

评论回复
151
t60yz|  楼主 | 2023-11-22 12:01 | 只看该作者
1.5.2 连续转换,非扫描模式

使用特权

评论回复
152
t60yz|  楼主 | 2023-11-22 12:01 | 只看该作者
1.5.2 连续转换,非扫描模式


使用特权

评论回复
153
t60yz|  楼主 | 2023-11-22 12:02 | 只看该作者
1.5.3 单次转换,扫描模式


使用特权

评论回复
154
t60yz|  楼主 | 2023-11-22 12:02 | 只看该作者
1.5.4 连续转换,扫描模式


使用特权

评论回复
155
t60yz|  楼主 | 2023-11-22 12:02 | 只看该作者
1.6 ADC的触发方式(软件,硬件)

使用特权

评论回复
156
t60yz|  楼主 | 2023-11-22 12:02 | 只看该作者
1.7 ADC的数据处理、转换时间、校准

使用特权

评论回复
157
t60yz|  楼主 | 2023-11-22 12:02 | 只看该作者

使用特权

评论回复
158
t60yz|  楼主 | 2023-11-22 12:03 | 只看该作者
2.代码配置
2.1 ADC单通道模式
单次转换、非连续模式
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "ADC.h"
#include "Delay.h"

/***************************************************/ADC模块
#include "stm32f10x.h"                  // Device header
#include "ADC.h"


void ADC_init(void)
{
        //1.先使能时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
       
        //2.设置ADC的分频
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);
       
        //3.配置GPIO口PA0
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStruct);
       
        //4.确定规则组或注入组的通道
        ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_28Cycles5);
       
        //5.初始化ADC
        ADC_InitTypeDef ADC_InitStruct;
        ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//配置是否连续触发模式
        ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//选择数据对齐模式为右对齐
        ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//选择外界触发源
        ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//配置是ADC是几个同时工作还是独立工作
        ADC_InitStruct.ADC_NbrOfChannel=1;//确定要输入的组的个数
        ADC_InitStruct.ADC_ScanConvMode=DISABLE;//是否连续扫描模式
        ADC_Init(ADC1, &ADC_InitStruct);
       
        //6.打开ADC
        ADC_Cmd(ADC1,ENABLE);
       
        //7.校准ADC
        ADC_ResetCalibration(ADC1);//1.复位校准
        while(ADC_GetResetCalibrationStatus(ADC1));//2.等待复位校准完成
        ADC_StartCalibration(ADC1);//3.开始校准
        while(ADC_GetCalibrationStatus(ADC1));//4.等待校准完成
}

uint16_t get_adcvalue(void)
{
        ADC_SoftwareStartConvCmd(ADC1,ENABLE);//触发开始ADC读值
        while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//读取EOC标志位,当转化读取完成后退出循环
        return ADC_GetConversionValue(ADC1);//读取ADC寄存器,自动清除EOC标志位
}

/***************************************************/延时函数
#include "Delay.h"
#include "stm32f10x.h"

/**
  * @brief  微秒级延时
  * @param  xus 延时时长,范围:0~233015
  * @retval 无
  */
void Delay_us(uint32_t xus)
{
        SysTick->LOAD = 72 * xus;                                //设置定时器重装值
        SysTick->VAL = 0x00;                                        //清空当前计数值
        SysTick->CTRL = 0x00000005;                                //设置时钟源为HCLK,启动定时器
        while(!(SysTick->CTRL & 0x00010000));        //等待计数到0
        SysTick->CTRL = 0x00000004;                                //关闭定时器
}

/**
  * @brief  毫秒级延时
  * @param  xms 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_ms(uint32_t xms)
{
        while(xms--)
        {
                Delay_us(1000);
        }
}

/**
  * @brief  秒级延时
  * @param  xs 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_s(uint32_t xs)
{
        while(xs--)
        {
                Delay_ms(1000);
        }
}

/***************************************************/主函数

uint16_t ADCvalue;//旋钮值
float  Voltage;//转换成电压值
int main(void)
{
        OLED_Init();
        ADC_init();
        OLED_ShowString(1,1,"Hello,my honey");

        OLED_ShowString(2, 1, "ADValue:");
        OLED_ShowString(3, 1, "Volatge:0.00V");
        while(1)
        {
                ADCvalue=get_adcvalue();
                Voltage = (float)ADCvalue / 4095 * 3.3;
               
                OLED_ShowNum(2, 9, ADCvalue, 4);
                OLED_ShowNum(3, 9, Voltage, 1);//这里将电压值按整数部分和小数部分两部分取出来
                OLED_ShowNum(3, 11, (uint16_t)(Voltage * 100) % 100, 2);
               
                Delay_ms(100);;
        }
}



使用特权

评论回复
159
t60yz|  楼主 | 2023-11-22 12:03 | 只看该作者
.简单实现ADC多通道
每次改变序号里的通道即可;


#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "ADC.h"
#include "Delay.h"

/***************************************************/ADC
#include "stm32f10x.h"                  // Device header
#include "ADC.h"


void ADC_init(void)
{
        //1.先使能时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
       
        //2.设置ADC的分频
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);
       
        //3.配置GPIO口PA0
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStruct);
       
        //4.确定规则组或注入组的通道
//        ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_28Cycles5);
       
        //5.初始化ADC
        ADC_InitTypeDef ADC_InitStruct;
        ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//配置是否连续触发模式
        ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//选择数据对齐模式为右对齐
        ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//选择外界触发源
        ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//配置是ADC是几个同时工作还是独立工作
        ADC_InitStruct.ADC_NbrOfChannel=1;//确定要输入的组的个数
        ADC_InitStruct.ADC_ScanConvMode=DISABLE;//是否连续扫描模式
        ADC_Init(ADC1, &ADC_InitStruct);
       
        //6.打开ADC
        ADC_Cmd(ADC1,ENABLE);
       
        //7.校准ADC
        ADC_ResetCalibration(ADC1);//1.复位校准
        while(ADC_GetResetCalibrationStatus(ADC1));//2.等待复位校准完成
        ADC_StartCalibration(ADC1);//3.开始校准
        while(ADC_GetCalibrationStatus(ADC1));//4.等待校准完成
}

uint16_t get_adcvalue(uint8_t ADC_Channel)
{
                ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_28Cycles5);

        ADC_SoftwareStartConvCmd(ADC1,ENABLE);//触发开始ADC读值
        while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//读取EOC标志位,当转化读取完成后退出循环
        return ADC_GetConversionValue(ADC1);//读取ADC寄存器,自动清除EOC标志位
}
     
/***************************************************/延时
#include "Delay.h"
#include "stm32f10x.h"

/**
  * @brief  微秒级延时
  * @param  xus 延时时长,范围:0~233015
  * @retval 无
  */
void Delay_us(uint32_t xus)
{
        SysTick->LOAD = 72 * xus;                                //设置定时器重装值
        SysTick->VAL = 0x00;                                        //清空当前计数值
        SysTick->CTRL = 0x00000005;                                //设置时钟源为HCLK,启动定时器
        while(!(SysTick->CTRL & 0x00010000));        //等待计数到0
        SysTick->CTRL = 0x00000004;                                //关闭定时器
}

/**
  * @brief  毫秒级延时
  * @param  xms 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_ms(uint32_t xms)
{
        while(xms--)
        {
                Delay_us(1000);
        }
}

/**
  * @brief  秒级延时
  * @param  xs 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_s(uint32_t xs)
{
        while(xs--)
        {
                Delay_ms(1000);
        }
}

/***************************************************/主函数
uint16_t key,light;

int main(void)
{
        OLED_Init();
        ADC_init();
        OLED_ShowString(1,1,"Hello,my honey");
//        OLED_ShowString(2,1,"Hello WangFang");
//        OLED_ShowString(3,1,"Hello Tomorrow");
//        OLED_ShowString(4,1,"I miss you");

        while(1)
        {
                key=get_adcvalue(ADC_Channel_0);
                light=get_adcvalue(ADC_Channel_1);
               
                OLED_ShowNum(2,1,key,5);
                OLED_ShowNum(3,1,light,5);
        }
}


使用特权

评论回复
160
t60yz|  楼主 | 2023-11-22 12:03 | 只看该作者
3.DMA实现数据迁移
**1.结构原理

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则