OC中self.a和_a的访问的区别

本文详细解释了Objective-C中@property和@synthesize的用途及其区别,并通过实例演示了self.a与_a访问方式的不同效果,强调了使用self.a的优势。

久了不回顾基础知识,猛然间看到,有时候还真想不起来有的知识,比如声明@property和合成@synthesize的属性与普通的属性有什么本质区别,self.a和_a访问的区别,所以有必要回顾一下。


我们先来说说@property和@synthesize
@property声明成员变量,会自动帮我们生成该成员变量的getter/setter方法的声明;
@synthesize的作用是自动生成成员变量的getter/setter方法的定义;
所有被声明为属性的成员,在iOS5 之前需要使用编译器指令@synthesize 来告诉编译器帮助生成属性的getter,setter方法。之后这个指令可以不用人为指定了,默认情况下编译器会帮我们生成。
这里先浅显的说明@property和synthesize的作用,其他的知识自己google,今天主要回顾self.a和_a的区别。


首先使用self.a会调用getter/setter方法,而_a并不会调用getter/setter方法,它是直接访问实例变量并赋值。
下面我们通过@property的copy属性举例说明:

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *sex;

- (void)changeNameValue:(NSString *)newName andChangeSexValue:(NSString *)sexValue;

@end

上面是一个Person类,里面有两个成员变量name和sex,声明了一个实例方法changeNameValue:andChangeSexValue:,下面实例方法的实现:

#import "Person.h"

@implementation Person

- (void)changeNameValue:(NSString *)newName andChangeSexValue:(NSString *)sexValue
{
    self.name = newName;
    _sex = sexValue;
}

@end

然后在viewDidLoad方法中调用:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableString *newName =[NSMutableString stringWithString:@"TongRy"];
    NSMutableString *newSex = [NSMutableString stringWithString:@"man"];

    Person *xiaoming = [[Person alloc] init];
    [xiaoming changeNameValue:newName andChangeSexValue:newSex];

    NSLog(@"xiaoming newName: %@, newSex: %@;", xiaoming.name, xiaoming.sex);

    [newName appendString:@"Good"];
    [newSex appendString:@"andwoman"];
    NSLog(@"To observe the changes : xiaoming name: %@, sex: %@;", xiaoming.name, xiaoming.sex);

}

运行后得到的结果:

运行结果


我们可以看到,newName和newSex改变了,name的值仍然没有变是TongRy,而sex的值确是改变了,末尾增加了“andwoman”.

实际上我们期待的是对类属性的赋值是深拷贝赋值(我们声明了@property的copy属性),但是实际得到的结果是name进行了深拷贝,而sex仍然是浅拷贝。究其原因,就是因为name是self访问,sex是_访问。在调用self的时候,如果是赋值,那么编译器会自动根据strong/copy生成对应的setter方法,其实现类似于:

//声明为copy属性时
- (void)setName:(NSString *)name
{
    if (_name != name)
    {
        [_name release];
        _name = [name copy];
    }
}

//当声明为retain属性时(MRC下)
- (void)setName:(NSString *)name
{
    if (_name != name)
    {
        [_name release];
        [name retain];
        _name = name;
    }
}

在上面的例子中,使用self.name赋值后,name已经和newName没有指向同一块内存,所以name没有随着newName值的改变而改变。_sex赋值是直接指向了newSex所指向的内存块,也没有做retain操作,容易出现问题。所以,我们在类中应该尽量使用self.a的形式来访问属性。

用self.name 是更好的选择,因为这样可以兼容懒加载,同时也避免了使用下划线的时候忽视了self这个指针,后者容易在block中造成循环引用。同时,使用_是获取不到父类的属性,因为它只是对局部变量的访问。



 

我用万用表测出来PA4的电压是0.74左右,可oled屏上显示的电压是0.22左右#include "stm32f4xx.h" #include "delay.h" #include "oled.h" #include "stdio.h" #include "stdlib.h" #include "arm_math.h" #include "pid.h" #include "./adc/bsp_adc.h" #include "tim.h" #include "bsp_GeneralTim.h" float pid_out; float Vout_actual = 0.0f; float Target = 12.0f; // 目标输出电压 float voltage1; uint32_t time = 0; // ms 计时变量 // 全局PID控制器 PID_Controller pid; extern __IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]; extern uint16_t TIM1_Impluse ;//高级定时器占空比 extern volatile uint8_t adc_data_ready ; extern volatile uint8_t tim_update_flag; extern volatile uint32_t last_adc_value ; int main(void) { OLED_Init(); Adc_Init(); TIM_Init(); GENERAL_TIM_Init(); // 输入20V→输出15V:kp=0.3-0.6, ki=0.05-0.2, kd=0.01-0.05 //输入35V→输出20V:kp=0.2-0.4, ki=0.02-0.1, kd=0.005-0.02 pid.kp = 0.5f; // 从较小值开始调试 pid.ki = 0.1f; pid.kd = 0.01f; pid.max_output = 100.0f; pid.min_output = 0.0f; pid.integral = 0; pid.prev_error = 0; while(1) { if(tim_update_flag) { // 直接读取全局ADC值 Vout_actual = ADC_ConvertedValue[0] * 3.3f * 0.000244140625; // 使用PID计算 pid_out = pid_control(&pid, Target, Vout_actual); // 安全更新PWM (限制在0-8400) TIM1_Impluse = (uint16_t)(pid_out * 84); if(TIM1_Impluse > 8400) TIM1_Impluse = 8400; TIM1->CCR1 = TIM1_Impluse; tim_update_flag=0; } // 显示刷新 static char display_buffer[2][40]; snprintf(display_buffer[0], 40, "Vout: %.2fV", Vout_actual); snprintf(display_buffer[1], 40, "Duty: %d", TIM1->CCR1); OLED_ShowString(0, 1, (u8*)display_buffer[0], 12); OLED_ShowString(0, 18, (u8*)display_buffer[1], 12); OLED_Refresh_Gram(); if ( time == 10 ) /* 10 * 1 ms = 10s 时间到 */ { time = 0; } } } #include "stm32f4xx_it.h" #include "oled.h" #include <math.h> #include "./adc/bsp_adc.h" #include "pid.h" #include "bsp_GeneralTim.h" extern uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]; extern float voltage1; extern float pid_out; extern float Vout_actual; extern uint16_t TIM1_Impluse ;//高级定时器占空比 volatile uint8_t adc_data_ready = 0; volatile uint8_t tim_update_flag=0 ; volatile uint32_t last_adc_value = 0; extern volatile uint32_t time; extern float Target; // 全局PID控制器 extern PID_Controller pid; void TIM1_UP_TIM10_IRQHandler(void) { if(TIM_GetITStatus(TIM1,TIM_IT_Update) == SET) { if(adc_data_ready) { // 设置处理标志 tim_update_flag = 1; // 清除ADC就绪标志 adc_data_ready = 0; } TIM_ClearITPendingBit(TIM1, TIM_IT_Update); } } void DMA2_Stream0_IRQHandler(void) { // 处理传输完成中断 if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)) { adc_data_ready = 1; // 清除标志的正确方法 DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); } } void GENERAL_TIM_IRQHandler (void) { if ( TIM_GetITStatus( GENERAL_TIM, TIM_IT_Update) != RESET ) { time++; TIM_ClearITPendingBit(GENERAL_TIM , TIM_FLAG_Update); } } void NMI_Handler(void) { } void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ while (1) {} } void MemManage_Handler(void) { /* Go to infinite loop when Memory Manage exception occurs */ while (1) {} } void BusFault_Handler(void) { /* Go to infinite loop when Bus Fault exception occurs */ while (1) {} } void UsageFault_Handler(void) { /* Go to infinite loop when Usage Fault exception occurs */ while (1) {} } void DebugMon_Handler(void) { } void SVC_Handler(void) { } void PendSV_Handler(void) { } void SysTick_Handler(void) { } #include "tim.h" uint16_t TIM1_Impluse = 4200;//预设占空比 float z = 0; const uint32_t spwm[400] = { 4200,4265,4331,4397,4463,4529,4595,4660,4726,4791,4857,4922,4987,5051,5116,5180, 5244,5308,5371,5434,5497,5560,5622,5684,5746,5807,5868,5928,5988,6047,6106,6165, 6223,6280,6337,6394,6450,6505,6560,6615,6668,6721,6774,6826,6877,6927,6977,7026, 7075,7122,7169,7216,7261,7306,7350,7393,7436,7477,7518,7558,7597,7636,7673,7710, 7746,7781,7815,7848,7880,7911,7942,7971,8000,8027,8054,8080,8105,8128,8151,8173, 8194,8214,8233,8251,8268,8283,8298,8312,8325,8337,8348,8358,8366,8374,8381,8387, 8391,8395,8397,8399,8400,8399,8397,8395,8391,8387,8381,8374,8366,8358,8348,8337, 8325,8312,8298,8283,8268,8251,8233,8214,8194,8173,8151,8128,8105,8080,8054,8027, 8000,7971,7942,7911,7880,7848,7815,7781,7746,7710,7673,7636,7597,7558,7518,7477, 7436,7393,7350,7306,7261,7216,7169,7122,7075,7026,6977,6927,6877,6826,6774,6721, 6668,6615,6560,6505,6450,6394,6337,6280,6223,6165,6106,6047,5988,5928,5868,5807, 5746,5684,5622,5560,5497,5434,5371,5308,5244,5180,5116,5051,4987,4922,4857,4791, 4726,4660,4595,4529,4463,4397,4331,4265,4200,4134,4068,4002,3936,3870,3804,3739, 3673,3608,3542,3477,3412,3348,3283,3219,3155,3091,3028,2965,2902,2839,2777,2715, 2653,2592,2531,2471,2411,2352,2293,2234,2176,2119,2062,2005,1949,1894,1839,1784, 1731,1678,1625,1573,1522,1472,1422,1373,1324,1277,1230,1183,1138,1093,1049,1006, 963,922,881,841,802,763,726,689,653,618,584,551,519,488,457,428, 399,372,345,319,294,271,248,226,205,185,166,148,131,116,101,87, 74,62,51,41,33,25,18,12,8,4,2,0,0,0,2,4, 8,12,18,25,33,41,51,62,74,87,101,116,131,148,166,185, 205,226,248,271,294,319,345,372,399,428,457,488,519,551,584,618, 653,689,726,763,802,841,881,922,963,1006,1049,1093,1138,1183,1230,1277, 1324,1373,1422,1472,1522,1573,1625,1678,1731,1784,1839,1894,1949,2005,2062,2119, 2176,2234,2293,2352,2411,2471,2531,2592,2653,2715,2777,2839,2902,2965,3028,3091, 3155,3219,3283,3348,3412,3477,3542,3608,3673,3739,3804,3870,3936,4002,4068,4134 }; //TIM1的GPIO static void TIM_GPIO_Config(void) { GPIO_InitTypeDef TIM_GPIO_InitStruct; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);//开钟 /*-----------------------------PA8,PA7------------------------------------*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1);//引脚复用 主 PA8,PA7 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); /*-----------------------------------------------------------------------*/ /*-----------------------------PA9,PB14------------------------------------*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_TIM1);//引脚复用 主 GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14; GPIO_Init(GPIOB, &TIM_GPIO_InitStruct); /*-----------------------------------------------------------------------*/ /*-----------------------------PA10,PB1------------------------------------*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_TIM1);//引脚复用 主 GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; GPIO_Init(GPIOB, &TIM_GPIO_InitStruct); /*-----------------------------------------------------------------------*/ // TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; //模拟模式 pa6死刹 // TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; //引脚 // TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 // TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 // TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //浮空 // GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 } //TIM1 static void TIM_A1_Mode_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStruct; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);///使能时钟 //168MHZ->20kHZ 主频/(计数+1)*(预分频系数+1) //168MHz/8 * 1050 = 20khz /*-----------------------------基本结构体------------------------------------*/ TIM_TimeBaseInitStructure.TIM_Period = (8400-1); //自动重装载值 TIM_TimeBaseInitStructure.TIM_Prescaler=(1-1); //定时器分频 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //1分频 TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; //不需要重复计数 TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure); //初始化TIM /*-----------------------------基本结构体------------------------------------*/ /*-----------------------------输出比较------------------------------------*/ TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //pwm模式选择 TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; ///使能输出通道 TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Enable; //使能互补通道 TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; //预设占空比 TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //PWM12中的CHCCR之间值的大小(多用pwm1的模式1) TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High; //当使用了刹车功能时,两路PWM12都会被强制禁止,进而输出我们配置的的空闲先状态 TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; //刹车时输出通道的状态 Set = high TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //刹车时互补通道的状态 Reset = low TIM_OC1Init(TIM1, &TIM_OCInitStruct); //使能通道1 TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); /* 使能通道1重载 */ TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; TIM_OC2Init(TIM1, &TIM_OCInitStruct); TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable); TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; TIM_OC3Init(TIM1, &TIM_OCInitStruct); TIM_OC3PreloadConfig(TIM1,TIM_OCPreload_Enable); /*-----------------------------输出比较------------------------------------*/ /*-----------------------------死区刹车------------------------------------*/ TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; //开启死区 TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; //开启1空闲状态 TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; //不同的锁定级别 (看BDTR寄存器) TIM_BDTRInitStructure.TIM_DeadTime = 20; //刹车时间,(看BDTR寄存器中的DTG[7:0]) //11转换成二进制为0000 1011 死区时间看[7;5]位,此处为000 TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable; //允许刹车 //BKIN 测到低电平 比较信号禁止 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; //高极性 TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; //自动输出使能(刹车输入无效) TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); //写入 /*-----------------------------死区刹车------------------------------------*/ TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); //允许定时器更新中断 | TIM_IT_Trigger TIM_Cmd(TIM1,ENABLE); //使能定时器 TIM_CtrlPWMOutputs(TIM1, ENABLE); //主动输出使能 } static void TIM_A1_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; /*-----------------------------中断------------------------------------*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //分组 NVIC_InitStructure.NVIC_IRQChannel=TIM1_UP_TIM10_IRQn; //定时器1中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure); //写入 /*-----------------------------中断------------------------------------*/ } void TIM_Init(void) { TIM_A1_NVIC_Config(); TIM_GPIO_Config(); TIM_A1_Mode_Config(); } #include "./adc/bsp_adc.h" __IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]={0}; extern volatile uint8_t adc_data_ready ; volatile uint8_t current_buffer = 0; static void ADC_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /*=====================通道1======================*/ // 使能 GPIO 时钟 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1,ENABLE); // 配置 IO GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //不上拉不下拉 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADC_GPIO_PORT1, &GPIO_InitStructure); } void ADC_DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; // 1. 使能 DMA 时钟 RCC_AHB1PeriphClockCmd(ADC_DMA_CLK, ENABLE); // 2. 配置 DMA 参数 DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL; // DMA 通道 0 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADC_ConvertedValue; // 目标地址:内存缓冲区 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // 内存缓冲区地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // 外设到内存 DMA_InitStructure.DMA_BufferSize = RHEOSTAT_NOFCHANEL; // 缓冲区大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不递增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址递增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 外设数据大小:半字(16位) DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 内存数据大小:半字(16位) DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 高优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // 禁用 FIFO 模式 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; // FIFO 阈值 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; // 内存突发传输:单次 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // 外设突发传输:单次 // 3. 初始化 DMA DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure); // 4. 使能 DMA 中断(传输完成、传输错误) DMA_ITConfig(ADC_DMA_STREAM, DMA_IT_TC | DMA_IT_TE | DMA_IT_HT, ENABLE); // 5. 使能 DMA 流 DMA_Cmd(ADC_DMA_STREAM, ENABLE); } void ADC_Config(void) { ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; // 1. 使能 ADC 时钟 RCC_APB2PeriphClockCmd(ADC_CLK, ENABLE); // 2. 配置 ADC 通用参数 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; // ADC 时钟分频:PCLK2/4 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; // DMA 访问模式 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; // 采样延迟 ADC_CommonInit(&ADC_CommonInitStructure); // 3. 配置 ADC 参数 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; // 12位分辨率 ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 扫描模式使能 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换模式 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // 无外部触发 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; // 外部触发源 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐 ADC_InitStructure.ADC_NbrOfConversion = RHEOSTAT_NOFCHANEL ; // 转换通道数 ADC_Init(ADC_, &ADC_InitStructure); // 4. 配置 ADC 通道(通道4,PA4) ADC_RegularChannelConfig(ADC_, ADC_Channel_4, 1, ADC_SampleTime_84Cycles); // 5. 使能 ADC DMA ADC_DMACmd(ADC_, ENABLE); // 6. 使能 ADC ADC_Cmd(ADC_, ENABLE); // 7. 启动 ADC 转换 ADC_SoftwareStartConv(ADC_); } static void ADC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } float ADC_ReadVoltage(void); void Adc_Init(void) { ADC_GPIO_Config(); ADC_DMA_Config(); ADC_Config(); ADC_NVIC_Config(); } // 在bsp_adc.c中实现电压读取 float ADC_ReadVoltage(void) { static uint8_t initialized = 0; if(!initialized) { Adc_Init(); initialized = 1; } // 直接读取全局数组 return ADC_ConvertedValue[0] * 3.3f * 0.000244140625; } #ifndef __BSP_ADC_H #define __BSP_ADC_H #include "stm32f4xx.h" #define RHEOSTAT_NOFCHANEL 1 /*=====================通道1 IO======================*/ // ADC IO宏定义 #define ADC_GPIO_PORT1 GPIOA #define ADC_GPIO_PIN1 GPIO_Pin_4 #define ADC_GPIO_CLK1 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL1 ADC_Channel_4 // ADC 序号宏定义 #define ADC_ ADC1 #define ADC_CLK RCC_APB2Periph_ADC1 // ADC DR寄存器宏定义,ADC转换后的数字值则存放在这里 #define RHEOSTAT_ADC_DR_ADDR ((u32)ADC1+0x4c) // ADC DMA 通道宏定义,这里我们使用DMA传输 // DMA 配置 #define ADC_DMA_CLK RCC_AHB1Periph_DMA2 #define ADC_DMA_CHANNEL DMA_Channel_0 #define ADC_DMA_STREAM DMA2_Stream0 void Adc_Init(void); float ADC_ReadVoltage(void); #endif /* __BSP_ADC_H */ #include "pid.h" float pid_control(PID_Controller* pid, float setpoint, float input) { // 计算当前误差 float error = setpoint - input; // 比例项 float p_term = pid->kp * error; // 积分项(带抗饱) pid->integral += error; // 积分限幅 if(pid->integral > pid->max_output) pid->integral = pid->max_output; else if(pid->integral < pid->min_output) pid->integral = pid->min_output; float i_term = pid->ki * pid->integral; // 微分项(标准实现) float d_term = pid->kd * (error - pid->prev_error); // PID输出 float output = p_term + i_term + d_term; // 输出限幅 if(output > pid->max_output) output = pid->max_output; else if(output < pid->min_output) output = pid->min_output; // 更新误差历史 pid->prev_error = error; return output; } #include "bsp_GeneralTim.h" // 中断优先级配置 static void GENERAL_TIM_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置中断来源 NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM_IRQ ; // 设置主优先级为 0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 设置抢占优先级为3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } ///* // * 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6TIM7的寄存器里面只有 // * TIM_PrescalerTIM_Period,所以使用TIM6TIM7的时候只需初始化这两个成员即可, // * 另外三个成员是通用定时器高级定时器才有. // *----------------------------------------------------------------------------- // *typedef struct // *{ TIM_Prescaler 都有 // * TIM_CounterMode TIMx,x[6,7]没有,其他都有 // * TIM_Period 都有 // * TIM_ClockDivision TIMx,x[6,7]没有,其他都有 // * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有 // *}TIM_TimeBaseInitTypeDef; // *----------------------------------------------------------------------------- // */ static void GENERAL_TIM_Mode_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 开启定时器时钟,即内部时钟CK_INT=72M GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK, ENABLE); // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_Period; // 时钟预分频数 TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_Prescaler; // 时钟分频因子 ,没用到不用管 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 计数器计数模式,设置为向上计数 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,没用到不用管 TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定时器 TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure); // 清除计数器中断标志位 TIM_ClearFlag(GENERAL_TIM, TIM_FLAG_Update); // 开启计数器中断 TIM_ITConfig(GENERAL_TIM,TIM_IT_Update,ENABLE); // 使能计数器 TIM_Cmd(GENERAL_TIM, ENABLE); } void GENERAL_TIM_Init(void) { GENERAL_TIM_NVIC_Config(); GENERAL_TIM_Mode_Config(); } /*********************************************END OF FILE**********************/ #ifndef __BSP_GENERALTIME_H #define __BSP_GENERALTIME_H #include "stm32f4xx.h" /**************通用定时器TIM参数定义,只限TIM2、3、4、5************/ // 当需要哪个定时器的时候,只需要把下面的宏定义改成1即可 #define GENERAL_TIM2 1 #define GENERAL_TIM3 0 #define GENERAL_TIM4 0 #define GENERAL_TIM5 0 #if GENERAL_TIM2 #define GENERAL_TIM TIM2 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM2 #define GENERAL_TIM_Period (1000-1) #define GENERAL_TIM_Prescaler 71 #define GENERAL_TIM_IRQ TIM2_IRQn #define GENERAL_TIM_IRQHandler TIM2_IRQHandler #elif GENERAL_TIM3 #define GENERAL_TIM TIM3 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM3 #define GENERAL_TIM_Period (1000-1) #define GENERAL_TIM_Prescaler 71 #define GENERAL_TIM_IRQ TIM3_IRQn #define GENERAL_TIM_IRQHandler TIM3_IRQHandler #elif GENERAL_TIM4 #define GENERAL_TIM TIM4 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM4 #define GENERAL_TIM_Period (1000-1) #define GENERAL_TIM_Prescaler 71 #define GENERAL_TIM_IRQ TIM4_IRQn #define GENERAL_TIM_IRQHandler TIM4_IRQHandler #elif GENERAL_TIM5 #define GENERAL_TIM TIM5 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM5 #define GENERAL_TIM_Period (1000-1) #define GENERAL_TIM_Prescaler 71 #define GENERAL_TIM_IRQ TIM5_IRQn #define GENERAL_TIM_IRQHandler TIM5_IRQHandler #endif /**************************函数声明********************************/ void GENERAL_TIM_Init(void); #endif /* __BSP_GENERALTIME_H */
07-12
为什么改成下午这样,oled屏都不亮了#include "stm32f4xx.h" #include "delay.h" #include "oled.h" #include "stdio.h" #include "stdlib.h" #include "arm_math.h" #include "pid.h" #include "./adc/bsp_adc.h" #include "tim.h" #include "bsp_GeneralTim.h" float pid_out = 0; float Vout_actual = 0; //extern __IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]; uint32_t time = 0; // ms 计时变量 extern volatile uint8_t adc_data_ready; extern volatile uint8_t tim_update_flag; extern volatile uint32_t last_adc_value; float six = 0; // 全局状态变量 enum {STATE_INIT, STATE_RUNNING, STATE_FAULT} system_state = STATE_INIT; int main(void) { // 初始化外设 Adc_Init(); TIM_Init(); OLED_Init(); TIM2_Init(); // 启动转换 ADC_SoftwareStartConv(ADC1); while(1) { // 状态机管理 switch(system_state) { case STATE_INIT: if ( time == 1000 ) /* 1000 * 1 ms = 1s 时间到 */ { time = 0; TIM_CtrlPWMOutputs(TIM1, ENABLE); system_state = STATE_RUNNING; } break; case STATE_RUNNING: // 过压保护 if(Vout_actual > 15.0f) { char st[40]; TIM_CtrlPWMOutputs(TIM1, DISABLE); system_state = STATE_FAULT; OLED_ShowString(WORD_WIDTH*0,WORD_HIGH*4,(u8 *)st,WORD_SIZE); } break; case STATE_FAULT: // 需要手动复位 break; } } } void TIM2_IRQHandler(void) { if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET ) { char str[40]; sprintf(str,"Vout = %.3f",Vout_actual); OLED_ShowString(WORD_WIDTH*0,WORD_HIGH*0,(u8 *)str,WORD_SIZE); sprintf(str,"Duty = %.3f",pid_out); OLED_ShowString(WORD_WIDTH*0,WORD_HIGH*1,(u8 *)str,WORD_SIZE); sprintf(str,"test = %.3f",six); OLED_ShowString(WORD_WIDTH*0,WORD_HIGH*2,(u8 *)str,WORD_SIZE); OLED_Refresh_Gram(); sprintf(str,"TIM1->CCR2 = %d",TIM1->CCR2); OLED_ShowString(WORD_WIDTH*0,WORD_HIGH*3,(u8 *)str,WORD_SIZE); OLED_Refresh_Gram(); } TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } #include "stm32f4xx_it.h" #include "oled.h" #include <math.h> #include "./adc/bsp_adc.h" #include "pid.h" #include "bsp_GeneralTim.h" #include "bsp_GeneralTim.h" float Taget=12; extern float voltage1; extern float pid_out; extern float Vout_actual; extern uint16_t TIM1_Impluse;//高级定时器占空比 volatile uint8_t adc_data_ready = 0; volatile uint8_t tim_update_flag=0 ; volatile uint32_t last_adc_value = 0; extern volatile uint32_t time; extern float six; // PID计算(使用新的PID控制器) static PIDController pid; // 在DMA中断中仅设置标志 void DMA2_Stream0_IRQHandler(void) { if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)) { adc_data_ready = 1; // 仅设置标志 DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); } } void TIM1_UP_TIM10_IRQHandler(void) { if (TIM_GetITStatus(TIM1, TIM_IT_Update)) { if (adc_data_ready) { uint32_t sum = 0; for (int i=0; i<ADC_BUFFER_SIZE; i++) { sum += ADC_ConvertedValue[i]; } Vout_actual = (sum * 3.3f) / (ADC_BUFFER_SIZE * 4096.0f); adc_data_ready = 0; static uint8_t pid_initialized = 0; if (!pid_initialized) { PID_Init(&pid, 2.6f, 1.5f, 0.1f, 100.0f, 0.0f); pid_initialized = 1; } pid_out = PID_Compute(&pid, 12.0f, Vout_actual); // 计算占空比:pid_out是百分比,所以乘以(ARR+1)再除以100 TIM1_Impluse = (uint16_t)(pid_out * (TIM1->ARR + 1) / 100.0f); // 限幅保护(实际上PID输出已经限幅,这里可以省略,但为了安全) if (TIM1_Impluse > TIM1->ARR) TIM1_Impluse = TIM1->ARR; // 更新PWM(注意:我们只更新通道1,即PA8,其他通道可以不用更新) TIM1->CCR1 = TIM1_Impluse; // 同时更新其他通道(如果硬件上需要同步更新) // TIM1->CCR2 = TIM1_Impluse; // TIM1->CCR3 = TIM1_Impluse; } TIM_ClearITPendingBit(TIM1, TIM_IT_Update); } } void GENERAL_TIM_IRQHandler (void) { if ( TIM_GetITStatus( GENERAL_TIM, TIM_IT_Update) != RESET ) { time++; TIM_ClearITPendingBit(GENERAL_TIM , TIM_FLAG_Update); } } void NMI_Handler(void) { } void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ while (1) {} } void MemManage_Handler(void) { /* Go to infinite loop when Memory Manage exception occurs */ while (1) {} } void BusFault_Handler(void) { /* Go to infinite loop when Bus Fault exception occurs */ while (1) {} } void UsageFault_Handler(void) { /* Go to infinite loop when Usage Fault exception occurs */ while (1) {} } void DebugMon_Handler(void) { } void SVC_Handler(void) { } void PendSV_Handler(void) { } void SysTick_Handler(void) { } #include "tim.h" uint16_t TIM1_Impluse = 4200;//预设占空比 float z = 0; const uint32_t spwm[400] = { 4200,4265,4331,4397,4463,4529,4595,4660,4726,4791,4857,4922,4987,5051,5116,5180, 5244,5308,5371,5434,5497,5560,5622,5684,5746,5807,5868,5928,5988,6047,6106,6165, 6223,6280,6337,6394,6450,6505,6560,6615,6668,6721,6774,6826,6877,6927,6977,7026, 7075,7122,7169,7216,7261,7306,7350,7393,7436,7477,7518,7558,7597,7636,7673,7710, 7746,7781,7815,7848,7880,7911,7942,7971,8000,8027,8054,8080,8105,8128,8151,8173, 8194,8214,8233,8251,8268,8283,8298,8312,8325,8337,8348,8358,8366,8374,8381,8387, 8391,8395,8397,8399,8400,8399,8397,8395,8391,8387,8381,8374,8366,8358,8348,8337, 8325,8312,8298,8283,8268,8251,8233,8214,8194,8173,8151,8128,8105,8080,8054,8027, 8000,7971,7942,7911,7880,7848,7815,7781,7746,7710,7673,7636,7597,7558,7518,7477, 7436,7393,7350,7306,7261,7216,7169,7122,7075,7026,6977,6927,6877,6826,6774,6721, 6668,6615,6560,6505,6450,6394,6337,6280,6223,6165,6106,6047,5988,5928,5868,5807, 5746,5684,5622,5560,5497,5434,5371,5308,5244,5180,5116,5051,4987,4922,4857,4791, 4726,4660,4595,4529,4463,4397,4331,4265,4200,4134,4068,4002,3936,3870,3804,3739, 3673,3608,3542,3477,3412,3348,3283,3219,3155,3091,3028,2965,2902,2839,2777,2715, 2653,2592,2531,2471,2411,2352,2293,2234,2176,2119,2062,2005,1949,1894,1839,1784, 1731,1678,1625,1573,1522,1472,1422,1373,1324,1277,1230,1183,1138,1093,1049,1006, 963,922,881,841,802,763,726,689,653,618,584,551,519,488,457,428, 399,372,345,319,294,271,248,226,205,185,166,148,131,116,101,87, 74,62,51,41,33,25,18,12,8,4,2,0,0,0,2,4, 8,12,18,25,33,41,51,62,74,87,101,116,131,148,166,185, 205,226,248,271,294,319,345,372,399,428,457,488,519,551,584,618, 653,689,726,763,802,841,881,922,963,1006,1049,1093,1138,1183,1230,1277, 1324,1373,1422,1472,1522,1573,1625,1678,1731,1784,1839,1894,1949,2005,2062,2119, 2176,2234,2293,2352,2411,2471,2531,2592,2653,2715,2777,2839,2902,2965,3028,3091, 3155,3219,3283,3348,3412,3477,3542,3608,3673,3739,3804,3870,3936,4002,4068,4134 }; //TIM1的GPIO static void TIM_GPIO_Config(void) { GPIO_InitTypeDef TIM_GPIO_InitStruct; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);//开钟 /*-----------------------------PA8,PA7------------------------------------*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1);//引脚复用 主 PA8,PA7 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); /*-----------------------------------------------------------------------*/ /*-----------------------------PA9,PB14------------------------------------*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_TIM1);//引脚复用 主 GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14; GPIO_Init(GPIOB, &TIM_GPIO_InitStruct); /*-----------------------------------------------------------------------*/ /*-----------------------------PA10,PB1------------------------------------*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_TIM1);//引脚复用 主 GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; GPIO_Init(GPIOB, &TIM_GPIO_InitStruct); /*-----------------------------------------------------------------------*/ // TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; //模拟模式 pa6死刹 // TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; //引脚 // TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 // TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 // TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //浮空 // GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 } //TIM1 static void TIM_A1_Mode_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStruct; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);///使能时钟 //168MHZ->20kHZ 主频/(计数+1)*(预分频系数+1) //168MHz/8 * 1050 = 20khz /*-----------------------------基本结构体------------------------------------*/ TIM_TimeBaseInitStructure.TIM_Period = (8400-1); //自动重装载值 TIM_TimeBaseInitStructure.TIM_Prescaler=(1-1); //定时器分频 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //1分频 TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; //不需要重复计数 TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure); //初始化TIM /*-----------------------------基本结构体------------------------------------*/ /*-----------------------------输出比较------------------------------------*/ TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //pwm模式选择 TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; ///使能输出通道 TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Enable; //使能互补通道 TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; //预设占空比 TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //PWM12中的CHCCR之间值的大小(多用pwm1的模式1) TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High; //当使用了刹车功能时,两路PWM12都会被强制禁止,进而输出我们配置的的空闲先状态 TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; //刹车时输出通道的状态 Set = high TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //刹车时互补通道的状态 Reset = low TIM_OC1Init(TIM1, &TIM_OCInitStruct); //使能通道1 TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); /* 使能通道1重载 */ TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; TIM_OC2Init(TIM1, &TIM_OCInitStruct); TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable); TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; TIM_OC3Init(TIM1, &TIM_OCInitStruct); TIM_OC3PreloadConfig(TIM1,TIM_OCPreload_Enable); /*-----------------------------输出比较------------------------------------*/ /*-----------------------------死区刹车------------------------------------*/ TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; //开启死区 TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; //开启1空闲状态 TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; //不同的锁定级别 (看BDTR寄存器) TIM_BDTRInitStructure.TIM_DeadTime = 20; //刹车时间,(看BDTR寄存器中的DTG[7:0]) //11转换成二进制为0000 1011 死区时间看[7;5]位,此处为000 TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable; //允许刹车 //BKIN 测到低电平 比较信号禁止 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; //高极性 TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; //自动输出使能(刹车输入无效) TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); //写入 /*-----------------------------死区刹车------------------------------------*/ TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); //允许定时器更新中断 | TIM_IT_Trigger TIM_Cmd(TIM1,ENABLE); //使能定时器 TIM_CtrlPWMOutputs(TIM1, ENABLE); //主动输出使能 } static void TIM_A1_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; /*-----------------------------中断------------------------------------*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //分组 NVIC_InitStructure.NVIC_IRQChannel=TIM1_UP_TIM10_IRQn; //定时器1中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure); //写入 /*-----------------------------中断------------------------------------*/ } void TIM_Init(void) { TIM_A1_NVIC_Config(); TIM_GPIO_Config(); TIM_A1_Mode_Config(); } #include "./adc/bsp_adc.h" #include "bsp_GeneralTim.h" #include "stm32f4xx_adc.h" #define ADC_BUFFER_SIZE 32 __IO uint16_t ADC_ConvertedValue[ADC_BUFFER_SIZE] = {0}; // 修正数组大小 volatile uint8_t current_buffer = 0; volatile uint8_t adc_buffer_ready = 0; extern volatile uint32_t time; static void ADC_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /*=====================通道1======================*/ // 使能 GPIO 时钟 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1,ENABLE); // 配置 IO GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //不上拉不下拉 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADC_GPIO_PORT1, &GPIO_InitStructure); } void ADC_DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; // 1. 使能 DMA 时钟 RCC_AHB1PeriphClockCmd(ADC_DMA_CLK, ENABLE); // 2. 配置 DMA 参数 DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL; // DMA 通道 0 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADC_ConvertedValue; // 目标地址:内存缓冲区 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // 修正外设地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // 外设到内存 DMA_InitStructure.DMA_BufferSize = ADC_BUFFER_SIZE; // 缓冲区大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不递增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; // 单通道禁用地址递增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 外设数据大小:半字(16位) DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 内存数据大小:半字(16位) DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 高优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // 禁用 FIFO 模式 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; // FIFO 阈值 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; // 内存突发传输:单次 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // 外设突发传输:单次 // 3. 初始化 DMA DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure); // 4. 使能 DMA 中断(传输完成、传输错误) DMA_ITConfig(ADC_DMA_STREAM, DMA_IT_TC | DMA_IT_TE | DMA_IT_HT, ENABLE); // 5. 使能 DMA 流 DMA_Cmd(ADC_DMA_STREAM, ENABLE); } void ADC_Config(void) { ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; // 1. 使能 ADC 时钟 RCC_APB2PeriphClockCmd(ADC_CLK, ENABLE); // 2. 配置 ADC 通用参数 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; // ADC 时钟分频:PCLK2/4 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1 ; // DMA 访问模式 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; // 采样延迟 ADC_CommonInit(&ADC_CommonInitStructure); // 3. 配置 ADC 参数 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; // 12位分辨率 ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 扫描模式使能 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换模式 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // 软件触发 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; // 任意值 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐 ADC_InitStructure.ADC_NbrOfConversion = 1 ; // 转换通道数 ADC_Init(ADC_, &ADC_InitStructure); // 4. 配置 ADC 通道(通道4,PA4) ADC_RegularChannelConfig(ADC_, ADC_Channel_4, 1, ADC_SampleTime_84Cycles); // 5. 使能 ADC DMA ADC_DMACmd(ADC_, ENABLE); // 6. 使能 ADC ADC_Cmd(ADC_, ENABLE); // 7. 启动 ADC 转换 ADC_SoftwareStartConv(ADC_); } static void ADC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void Adc_Init(void) { ADC_GPIO_Config(); ADC_DMA_Config(); ADC_Config(); ADC_NVIC_Config(); } #ifndef __BSP_ADC_H #define __BSP_ADC_H #include "stm32f4xx.h" #define ADC_BUFFER_SIZE 32 // 增加缓冲区大小 extern __IO uint16_t ADC_ConvertedValue[ADC_BUFFER_SIZE]; // 在bsp_adc.c中定义 #define ADC_CHANNELS 1 /*=====================通道1 IO======================*/ // ADC IO宏定义 #define ADC_GPIO_PORT1 GPIOA #define ADC_GPIO_PIN1 GPIO_Pin_4 #define ADC_GPIO_CLK1 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL1 ADC_Channel_4 // ADC 序号宏定义 #define ADC_ ADC1 #define ADC_CLK RCC_APB2Periph_ADC1 // ADC DR寄存器宏定义,ADC转换后的数字值则存放在这里 #define RHEOSTAT_ADC_DR_ADDR ((u32)ADC1+0x4c) // ADC DMA 通道宏定义,这里我们使用DMA传输 // DMA 配置 #define ADC_DMA_CLK RCC_AHB1Periph_DMA2 #define ADC_DMA_CHANNEL DMA_Channel_0 #define ADC_DMA_STREAM DMA2_Stream0 void Adc_Init(void); float ADC_GetVoltage(void); //float ADC_ReadVoltage(void); #endif /* __BSP_ADC_H */ #include "pid.h" void PID_Init(PIDController* pid, float kp, float ki, float kd, float max, float min) { pid->kp = kp; pid->ki = ki; pid->kd = kd; pid->integral = 0; pid->prev_error = 0; pid->max_output = max; pid->min_output = min; } float PID_Compute(PIDController* pid, float setpoint, float input) { float error = setpoint - input; // 比例项 float p_term = pid->kp * error; // 积分项 pid->integral += error; // 积分限幅 if (pid->integral > pid->max_output) pid->integral = pid->max_output; else if (pid->integral < pid->min_output) pid->integral = pid->min_output; float i_term = pid->ki * pid->integral; // 微分项 float d_term = pid->kd * (error - pid->prev_error); // PID输出 float output = p_term + i_term + d_term; // 输出限幅 if (output > pid->max_output) output = pid->max_output; else if (output < pid->min_output) output = pid->min_output; // 更新误差历史 pid->prev_error = error; return output; } #include "bsp_GeneralTim.h" void TIM2_Init(void) { NVIC_InitTypeDef NVIC_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x01; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); TIM_TimeBaseInitStructure.TIM_Period = (168000-1); TIM_TimeBaseInitStructure.TIM_Prescaler= (1000-1); TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); TIM_ClearFlag(TIM2,TIM_FLAG_Update); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_ARRPreloadConfig(TIM2,ENABLE); TIM_Cmd(TIM2,ENABLE); } #include "bsp_GeneralTim.h" // 中断优先级配置 static void GENERAL_TIM_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3); // 设置中断来源 NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM_IRQ ; // 设置主优先级为 0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4; // 设置抢占优先级为3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } ///* // * 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6TIM7的寄存器里面只有 // * TIM_PrescalerTIM_Period,所以使用TIM6TIM7的时候只需初始化这两个成员即可, // * 另外三个成员是通用定时器高级定时器才有. // *----------------------------------------------------------------------------- // *typedef struct // *{ TIM_Prescaler 都有 // * TIM_CounterMode TIMx,x[6,7]没有,其他都有 // * TIM_Period 都有 // * TIM_ClockDivision TIMx,x[6,7]没有,其他都有 // * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有 // *}TIM_TimeBaseInitTypeDef; // *----------------------------------------------------------------------------- // */ static void GENERAL_TIM_Mode_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 开启定时器时钟,即内部时钟CK_INT=72M GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK, ENABLE); // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_Period; // 时钟预分频数 TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_Prescaler; // 时钟分频因子 ,没用到不用管 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 计数器计数模式,设置为向上计数 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,没用到不用管 TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定时器 TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure); // 清除计数器中断标志位 TIM_ClearFlag(GENERAL_TIM, TIM_FLAG_Update); // 开启计数器中断 TIM_ITConfig(GENERAL_TIM,TIM_IT_Update,ENABLE); // 使能计数器 TIM_Cmd(GENERAL_TIM, ENABLE); } void GENERAL_TIM_Init(void) { GENERAL_TIM_NVIC_Config(); GENERAL_TIM_Mode_Config(); } /*********************************************END OF FILE**********************/ #ifndef __BSP_GENERALTIME_H #define __BSP_GENERALTIME_H #include "stm32f4xx.h" /**************通用定时器TIM参数定义,只限TIM2、3、4、5************/ // 当需要哪个定时器的时候,只需要把下面的宏定义改成1即可 #define GENERAL_TIM2 0 #define GENERAL_TIM3 1 #define GENERAL_TIM4 0 #define GENERAL_TIM5 0 #if GENERAL_TIM2 #define GENERAL_TIM TIM2 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM2 #define GENERAL_TIM_Period (1000-1) #define GENERAL_TIM_Prescaler 71 #define GENERAL_TIM_IRQ TIM2_IRQn #define GENERAL_TIM_IRQHandler TIM2_IRQHandler #elif GENERAL_TIM3 #define GENERAL_TIM TIM3 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM3 #define GENERAL_TIM_Period (1000-1) #define GENERAL_TIM_Prescaler 71 #define GENERAL_TIM_IRQ TIM3_IRQn #define GENERAL_TIM_IRQHandler TIM3_IRQHandler #elif GENERAL_TIM4 #define GENERAL_TIM TIM4 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM4 #define GENERAL_TIM_Period (1000-1) #define GENERAL_TIM_Prescaler 71 #define GENERAL_TIM_IRQ TIM4_IRQn #define GENERAL_TIM_IRQHandler TIM4_IRQHandler #elif GENERAL_TIM5 #define GENERAL_TIM TIM5 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM5 #define GENERAL_TIM_Period (1000-1) #define GENERAL_TIM_Prescaler 71 #define GENERAL_TIM_IRQ TIM5_IRQn #define GENERAL_TIM_IRQHandler TIM5_IRQHandler #endif /**************************函数声明********************************/ void GENERAL_TIM_Init(void); void TIM2_Init(void); #endif /* __BSP_GENERALTIME_H */
最新发布
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值