打印
[STM32F1]

stm32(F103c8t6)自学笔记

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

使用特权

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

使用特权

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

使用特权

评论回复
124
t60yz|  楼主 | 2023-11-22 11:42 | 只看该作者
8种模式

TIM_OCMode                        函数库描述                             解释


TIM_OCMode_Timing       TIM输出比较                      冻结,输出比较不起作用
TIM_OOCMode_Active     TIM输出比较主动模式        当比较发生时,强制输出高电平
TIM_OCMode_Inactiive    TIM输出比较非主动模式     当比较发生时,强制输出低电平
TIM_OCMode_Toggle       TIM输出比较触发模式        当比较发生时,输出翻转
TIM_OCMode_PWM1        TIM脉冲宽度调制模式1      PWM1
TIM_OCMode_PWM2        TIM脉冲宽度调制模式2      PWM2

使用特权

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

使用特权

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

使用特权

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

使用特权

评论回复
128
t60yz|  楼主 | 2023-11-22 11:42 | 只看该作者
4.2 输出设备(舵机,直流电机)

使用特权

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

使用特权

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

使用特权

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

使用特权

评论回复
132
t60yz|  楼主 | 2023-11-22 11:43 | 只看该作者
4.3 代码配置
4.3.1(呼吸灯、重映射)
先和配置定时器步骤差不多,只不过最后不需要配置中断和NVIC,就直接配置CCR

CCR需要先使用TIM_OCStructInit()整体初始化,然后再单独配置需要的模式:

    TIM_OCInitTypeDef TIM_OCInitStruct;
    TIM_OCStructInit(&TIM_OCInitStruct);//先整体初始化,防止有些变量未初始化而出错
    TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置为PWM1输出模式
    TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF为高极性
    TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置输出使能
    TIM_OCInitStruct.TIM_Pulse=100;//配置CCR计数器值
    TIM_OC1Init(TIM2,&TIM_OCInitStruct);

重映射使用看视频学习

使用特权

评论回复
133
t60yz|  楼主 | 2023-11-22 11:43 | 只看该作者
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "PWM.h"
/***************************************************/PWM模块
#include "stm32f10x.h"                  // Device header
#include "Delay.h"


void pwm_init(void)
{
        //**1.打开总的RCC,要配置GPIO从而传入外部时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        //**2.配置PWM输出引脚
        GPIO_InitTypeDef GPIO_InitStruct;
       
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
       
        //**3.配置时基单元
        //配置为1000KHz,分辨率为1%
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
       
        TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
        TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
        TIM_TimeBaseInitStruct.TIM_Period=100-1;//设置预装载值       //外部时钟的话用不了这么高的频率
        TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//设置预分频值
        TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
        TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

        //**4.配置CCR
        TIM_OCInitTypeDef TIM_OCInitStruct;
        TIM_OCStructInit(&TIM_OCInitStruct);//先整体初始化,防止有些变量未初始化而出错
        TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置为PWM1输出模式
        TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF为高极性
        TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置输出使能
        TIM_OCInitStruct.TIM_Pulse=100;//配置CCR计数器值
        TIM_OC1Init(TIM2,&TIM_OCInitStruct);
       
        //5.开始计数
        TIM_Cmd(TIM2,ENABLE);
}

void LED_run(void)
{
        uint16_t num;
        for(num=100;num>0;num--)
        {
                TIM_SetCompare1(TIM2,num);
                Delay_ms(10);

        }
        for(num=0;num<100;num++)
        {
                TIM_SetCompare1(TIM2,num);
                Delay_ms(10);
        }
}

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

int main(void)
{
        OLED_Init();
        pwm_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)
        {
                LED_run();
        }
}

使用特权

评论回复
134
t60yz|  楼主 | 2023-11-22 11:43 | 只看该作者
4.3.2(旋钮控制舵机角度PWM)
旋转旋钮触发中断从而改变CCR的值(改变占空比)

要注意舵机的信号周期为20ms,既50Hz

使用特权

评论回复
135
t60yz|  楼主 | 2023-11-22 11:43 | 只看该作者
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "PWM.h"
#include "mokuaicount.h"

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


void pwm_init(void)
{
        //**1.打开总的RCC,要配置GPIO从而传入外部时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        //**2.配置PWM输出引脚PA0
        GPIO_InitTypeDef GPIO_InitStruct;
       
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
       
        //**3.配置时基单元
        //配置为1000KHz,分辨率为1%
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
       
        TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
        TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
        TIM_TimeBaseInitStruct.TIM_Period=20000-1;//设置预装载值       //外部时钟的话用不了这么高的频率
        TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//设置预分频值
        TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
        TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

        //**4.配置CCR
        TIM_OCInitTypeDef TIM_OCInitStruct;
        TIM_OCStructInit(&TIM_OCInitStruct);
        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=0;
        TIM_OC1Init(TIM2,&TIM_OCInitStruct);
       
        //5.
        //**6.开始计数
        TIM_Cmd(TIM2,ENABLE);
}

void set_angle(uint16_t angle)
{
        TIM_SetCompare1(TIM2,angle);
}

/***************************************************/GPIO初始化
#include "xuanniu.h"               
#include "stm32f10x.h"

void Xuanniu_init(uint16_t GPIO_Pin)//需要指定端口Pin进行模式设置
{
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE);//使能GPIOA的时钟
       
        GPIO_InitTypeDef Xuanniu_InitStruct;  

        Xuanniu_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//设置为 上拉输入 模式
        Xuanniu_InitStruct.GPIO_Pin=GPIO_Pin;  //外界参数设置Pin口
        Xuanniu_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz,在输入模式下该设置没用
        GPIO_Init( GPIOB,&Xuanniu_InitStruct); //以上三个都要传入该函数初始化
}

/***************************************************/计数模块
//**该模块由中断函数实现,可接入任意输入模式的模块实现计数
//**这里引入Key实现数据的减法,LightR实现加法
#include "stm32f10x.h"                  // Device header
#include "mokuaicount.h"
#include "Delay.h"
#include "xuanniu.h"


extern int num;

void Count_interrupt_init(void)
{
        //1、2、**步骤一二在模块内已经实现
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//AFIO时钟需要使能
       
        Xuanniu_init(GPIO_Pin_0|GPIO_Pin_1);
        //3**配置AFIO,选择输入引脚PB1(C),PB0(A)
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);//Xuanniu旋钮
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
        //4**配置EXTI寄存器,选择触发方式,这里配置EXTI和GPIO一样需要定义一个结构体
        EXTI_InitTypeDef EXTI_InitStruct;
        EXTI_InitStruct.EXTI_Line=EXTI_Line0|EXTI_Line1;
        EXTI_InitStruct.EXTI_LineCmd=ENABLE;
        EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
        EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
        EXTI_Init(&EXTI_InitStruct);
        //5**配置NVIC,选择合适的中断优先级 --------每一个外设要单独配置
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//要先分组,整个系统NVIC只分配一种模式
        //**配置Xuanniu A端
        NVIC_InitTypeDef NVIC_InitStruct_Xuanniu;
        NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI0_IRQn;
        NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
        NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
        NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
        NVIC_Init(&NVIC_InitStruct_Xuanniu);
        //**配置Xuanniu C端
        NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI1_IRQn;
        NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
        NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
        NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
        NVIC_Init(&NVIC_InitStruct_Xuanniu);
       
       
        //****所有配置完成
}

//中断位置随便放,也不需要声明
void EXTI0_IRQHandler()//正转触发
{
        if(EXTI_GetITStatus(EXTI_Line0)==SET)
        {
                if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0)
                {
                        if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==1)
                        {
                                num+=100;
                        }
                }
        }
        EXTI_ClearITPendingBit(EXTI_Line0);
}
void EXTI1_IRQHandler()
{
        if(EXTI_GetITStatus(EXTI_Line1)==SET)
        {
                if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)
                {
                        if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==1)
                        {
                                num-=100;
                        }
                }
        }
        EXTI_ClearITPendingBit(EXTI_Line1);
}


/***************************************************/主函数
int num=1500;

int main(void)
{
        OLED_Init();
        pwm_init();
        Count_interrupt_init();
        OLED_ShowString(1,1,"Hello,my baby");
        set_angle(num);//默认居中
        while(1)
        {       
                if(num<=0)
                {
                        num=0;
                        OLED_ShowString(2,8,"Left Max ");
                }
                else if(num<1500)
                {
                        OLED_ShowString(2,8,"Left     ");
                }
                else if(num==1500)
                {
                        OLED_ShowString(2,8,"Midel    ");
                }
                else if(num<2500)
                {
                        OLED_ShowString(2,8,"Right    ");
                }
                else if(num>=2500)
                {
                        num=2500;
                        OLED_ShowString(2,8,"Right Max");
                }
                OLED_ShowNum(2,1,num,5);
               
                set_angle(num);
        }
}

使用特权

评论回复
136
t60yz|  楼主 | 2023-11-22 11:44 | 只看该作者
4.3.3 直流电机(调速)
stay待机控制直接接入高电平3.3v就可以了

in1、in2初始化GPIO(推完输出模式)然后设置高低电平即可
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Motor.h"

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


void pwm_init(void)
{
        //**1.打开总的RCC,要配置GPIO从而传入外部时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        //**2.配置PWM输出引脚PA0
        GPIO_InitTypeDef GPIO_InitStruct;
       
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
       
        //**3.配置时基单元
        //配置为1000KHz,分辨率为1%
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
       
        TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
        TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
        TIM_TimeBaseInitStruct.TIM_Period=100-1;//设置预装载值       //外部时钟的话用不了这么高的频率
        TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//设置预分频值
        TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
        TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

        //**4.配置CCR
        TIM_OCInitTypeDef TIM_OCInitStruct;
        TIM_OCStructInit(&TIM_OCInitStruct);
        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=0;
        TIM_OC1Init(TIM2,&TIM_OCInitStruct);
       
        //5.开始计数
        TIM_Cmd(TIM2,ENABLE);
}

void set_num(uint16_t num)
{
        TIM_SetCompare1(TIM2,num);
}

/***************************************************/电机模块
#include "stm32f10x.h"                  // Device header
#include "Motor.h"
#include "PWM.h"

void Motor_init(void)
{
        pwm_init();
       
        GPIO_InitTypeDef GPIO_InitStruct;//初始化两个方向控制引脚:PA4,PA5
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
        GPIO_Init(GPIOA,&GPIO_InitStruct);
}

void set_speed(int speed)
{
        if(speed>=0)
        {
                set_num(speed);
                GPIO_SetBits(GPIOA,GPIO_Pin_4);
                GPIO_ResetBits(GPIOA,GPIO_Pin_5);
        }
        else
        {
                set_num(-speed);
                GPIO_SetBits(GPIOA,GPIO_Pin_5);
                GPIO_ResetBits(GPIOA,GPIO_Pin_4);
        }
}

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


int main(void)
{
        OLED_Init();
        Motor_init();
        while(1)
        {       
                set_speed(-100);
        }
}

使用特权

评论回复
137
t60yz|  楼主 | 2023-11-22 11:44 | 只看该作者
5.TIM输入捕获
5.1 结构原理
利用定时器模块计数,当输入捕获模块的边沿检测模块检测到下降沿或上升沿,触发获取CNT的值,每记完一次后CNT清零,获取到的该周期的CNT值再通过与CNT计数频率即可得到该电平变化周期的时间T。

由此可见,测频法适合测量高频,测周法适合测量低频

使用特权

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

使用特权

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

使用特权

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

使用特权

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

本版积分规则