活动介绍

typedef struct { unsigned char __pc0 : 1; unsigned char __pc1 : 1; unsigned char __pc2 : 1; unsigned char __pc3 : 1; unsigned char __pc4 : 1; unsigned char __pc5 : 1; unsigned char __pc6 : 1; unsigned char __pc7 : 1; } __pc_bits; typedef union { __pc_bits bits; __sfr_byte byte; } __pc_type; typedef struct { unsigned char __pcc0 : 1; unsigned char __pcc1 : 1; unsigned char __pcc2 : 1; unsigned char __pcc3 : 1; unsigned char __pcc4 : 1; unsigned char __pcc5 : 1; unsigned char __pcc6 : 1; unsigned char __pcc7 : 1; } __pcc_bits; typedef union { __pcc_bits bits; __sfr_byte byte; } __pcc_type;

时间: 2025-08-11 14:01:34 浏览: 19
<think>我们正在讨论C语言中的位字段(bit fields)结构体和联合体(union)。用户提到了两个特定的名称:`__pc_bits` 和 `__pcc_bits`,这可能是用户代码中定义的位字段结构体或联合体。 首先,我们需要解释位字段结构体和联合体的基本概念,然后结合这两个名称进行说明。 1. 位字段(Bit Fields): 位字段是C语言中一种特殊的数据结构,允许我们在结构体中以位为单位来指定成员变量所占用的内存大小。这种机制主要用于节省内存,特别是在资源受限的嵌入式系统中,或者需要与硬件寄存器进行精确匹配时。 定义位字段结构体的基本语法: ```c struct 结构体名 { 类型 [成员名] : 宽度; // ... 其他成员 }; ``` 例如: ```c struct Status { unsigned int flag1 : 1; // 1位 unsigned int flag2 : 1; // 1位 unsigned int count : 4; // 4位 }; ``` 这里,`flag1`和`flag2`各占1位,`count`占4位,整个结构体至少占用1个字节(但实际大小可能因对齐而增加)。 2. 联合体(Union): 联合体是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型。联合体的大小等于其最大成员的大小。联合体常用于节省内存,特别是在多个数据不会同时使用的情况下。 定义联合体的基本语法: ```c union 联合体名 { 类型 成员1; 类型 成员2; // ... }; ``` 3. 结合位字段和联合体: 我们可以将位字段结构体放在联合体中,这样可以通过不同的方式访问同一块内存。例如,我们可以用一个整数来访问整个位字段,也可以通过位字段结构体来访问每一位。 示例: ```c union ControlRegister { unsigned char byte; // 整个字节 struct { unsigned int mode : 2; // 最低两位 unsigned int enable : 1; // 第三位 unsigned int reserved : 5; // 剩余的5位 } bits; }; ``` 这样,我们可以通过`byte`成员访问整个寄存器,也可以通过`bits`成员访问各个位。 4. 关于用户提到的`__pc_bits`和`__pcc_bits`: 这可能是用户代码中定义的位字段结构体或联合体。通常,这样的命名可能用于表示某个特定寄存器的位字段。例如,在嵌入式系统中,外设寄存器经常被定义为位字段结构体,然后通过联合体与整数类型关联。 假设`__pc_bits`是一个位字段结构体,而`__pcc_bits`可能是另一个位字段结构体,或者它们都是联合体中的成员。 一个可能的例子(纯属猜测,因为用户没有给出具体定义): ```c union PCC_Register { uint32_t full; // 整个32位寄存器 struct { uint32_t mode : 3; uint32_t clock_div : 4; // ... 其他位 } __pcc_bits; }; union PC_Register { uint16_t half; struct { uint16_t pin0 : 1; // ... 其他引脚 } __pc_bits; }; ``` 5. 作用: 使用位字段结构体和联合体的主要目的是: - 节省内存空间。 - 提供对硬件寄存器的位级访问,使代码更易读和维护。 - 通过联合体,可以以整体或位字段的方式操作同一内存区域。 6. 注意事项: - 位字段的布局和内存对齐依赖于编译器和目标平台,因此可移植性可能受到影响。 - 位字段的成员不能取地址(因为最小的地址单位是字节)。 由于用户没有给出具体的定义,我们只能做一般性解释。如果用户能提供具体的定义,我们可以更精确地解释。 相关问题: 1. 位字段结构体在内存对齐方面有哪些注意事项? 2. 如何通过位字段操作硬件寄存器? 3. 联合体在类型双关(type punning)中有哪些应用? 4. 位字段结构体的大小计算规则是什么?</think>### C语言位字段结构体与联合体详解 #### 1. **位字段结构体(Bit-field)** 位字段允许在结构体中以**位(bit)** 为单位定义成员变量,用于精确控制内存布局和节省空间。语法示例: ```c struct __pc_bits { unsigned int flag1 : 1; // 占1位 unsigned int mode : 3; // 占3位 unsigned int resv : 4; // 占4位(保留位) }; ``` - **作用**: - 节省内存:例如8个布尔值只需1字节(而非8字节) - 硬件寄存器映射:精确匹配硬件寄存器位布局 - 数据压缩:如网络协议头处理 - **特点**: - 位宽限制:`int`型位宽不能超过数据类型本身位数(如32位系统≤32) - 内存对齐:受编译器对齐规则影响 - 不可取地址:`&struct.bit_field`非法(位无独立地址) #### 2. **联合体(Union)** 联合体使多个成员**共享同一内存空间**,同一时刻仅一个成员有效: ```c union Data { uint32_t raw; // 完整32位值 struct __pcc_bits bits;// 位字段结构体 }; ``` - **作用**: - 多视图访问:同一数据可按整体或位字段访问 - 类型转换:安全实现数据类型解释转换 - 内存复用:减少空间占用(大小=max(成员尺寸)) #### 3. **组合应用案例** 硬件寄存器访问场景: ```c // 定义位字段结构体 typedef struct { uint32_t en : 1; // 使能位 uint32_t clk_div: 4; // 时钟分频 uint32_t mode : 2; // 工作模式 } __pcc_bits; // 定义联合体 typedef union { uint32_t reg_value; // 寄存器整数值 __pcc_bits bits; // 位字段视图 } PCC_Register; // 使用示例 PCC_Register ctrl; ctrl.reg_value = 0xFFFF; // 直接写寄存器 ctrl.bits.clk_div = 0b1010; // 通过位字段修改分频值 ``` - **优势**: - 直接操作位:`ctrl.bits.en = 1` 比位掩码操作更直观 - 保证原子性:联合体操作是单内存访问 - 代码可读性:明确表达硬件位定义 #### 4. 关键注意事项 1. **移植性问题**: - 位字段布局依赖编译器实现(位顺序/对齐) - 跨平台时需显式指定`packed`属性: ```c struct __attribute__((packed)) __pc_bits {...}; ``` 2. **类型安全**: - 联合体访问非当前活跃成员属于未定义行为 - 建议通过`enum`标记当前有效成员 3. **性能影响**: - 位字段访问可能比整型操作慢(需移位/掩码) - 频繁操作位字段时需基准测试 #### 5. 典型应用场景 - 嵌入式系统:外设寄存器映射(如`ADC_CTRL`寄存器) - 通信协议:解析TCP头部标志位 - 驱动程序:设备状态寄存器监控 - 内存敏感系统:嵌入式数据库记录存储 > 示例中`__pc_bits`和`__pcc_bits`是典型的位字段结构体命名约定,常用于硬件抽象层(HAL)开发,前缀`__`通常表示编译器或系统级定义[^1]。 --- ### 相关问题 1. 如何保证位字段结构体在不同编译器下的内存布局一致性? 2. 联合体在实现变体数据类型(variant types)时有哪些最佳实践? 3. 位字段操作与位掩码操作在性能上有何差异? 4. 如何用联合体实现安全的数据类型转换(如浮点数到整型的位解释)? [^1]: 引用来源:C语言标准库实现中的常见命名规范。
阅读全文

相关推荐

#include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include <avr/eeprom.h> #include <string.h> #define delay_ms(x) _delay_ms(x) // LCD 相关引脚定义 #define LCD_RS PC0 #define LCD_RW PC1 #define LCD_E PC2 #define LCD_D4 PA4 #define LCD_D5 PA5 #define LCD_D6 PA6 #define LCD_D7 PA7 // 按键引脚定义(使用PORTD) #define SET_BUTTON PIND0 #define ADD_BUTTON PIND1 #define SUB_BUTTON PIND2 // LED 引脚定义 #define LED_PIN PB3 // EEPROM存储地址 #define EEPROM_TIME_HOUR_ADDR 0x00 #define EEPROM_TIME_MINUTE_ADDR 0x01 #define EEPROM_DATE_YEAR_ADDR 0x02 #define EEPROM_DATE_MONTH_ADDR 0x03 #define EEPROM_DATE_DAY_ADDR 0x04 // 全局变量 volatile uint8_t hour = 12; // 小时(0-23) volatile uint8_t minute = 0; // 分钟(0-59) volatile uint8_t second = 0; // 秒(0-59) volatile uint8_t year = 23; // 年份(后两位) volatile uint8_t month = 1; // 月份(1-12) volatile uint8_t day = 1; // 日期(1-31) volatile uint8_t set_mode = 0; // 0:正常显示, 1:设置小时, 2:设置分钟, 3:设置年, 4:设置月, 5:设置日 volatile uint8_t blink_state = 0; // 闪烁状态 volatile uint8_t timer1_counter = 0; // 定时器计数器 // 闹钟结构 typedef struct { uint8_t hour; uint8_t minute; uint8_t enabled; } Alarm; Alarm alarm1 = {8, 0, 0}; // 闹钟1,默认8:00,关闭 Alarm alarm2 = {12, 0, 0}; // 闹钟2,默认12:00,关闭 // LCD初始化 void LCD_Init() { // 设置数据端口为输出 DDRA |= (1<<LCD_D4) | (1<<LCD_D5) | (1<<LCD_D6) | (1<<LCD_D7); // 设置控制端口为输出 DDRC |= (1<<LCD_RS) | (1<<LCD_RW) | (1<<LCD_E); // 初始化序列 delay_ms(50); // 等待LCD上电稳定 // 4位模式初始化 LCD_Write_Command(0x33); LCD_Write_Command(0x32); LCD_Write_Command(0x28); // 4位模式,2行显示,5x8点阵 LCD_Write_Command(0x0C); // 显示开,光标关,闪烁关 LCD_Write_Command(0x06); // 增量模式,不移位 LCD_Write_Command(0x01); // 清屏 delay_ms(2); } // 向LCD发送命令 void LCD_Write_Command(unsigned char cmd) { PORTC &= ~(1<<LCD_RS); // RS=0 命令模式 PORTC &= ~(1<<LCD_RW); // RW=0 写入 // 发送高4位 PORTA = (PORTA & 0x0F) | (cmd & 0xF0); PORTC |= (1<<LCD_E); // E=1 delay_ms(1); PORTC &= ~(1<<LCD_E); // E=0 // 发送低4位 PORTA = (PORTA & 0x0F) | ((cmd << 4) & 0xF0); PORTC |= (1<<LCD_E); // E=1 delay_ms(1); PORTC &= ~(1<<LCD_E); // E=0 delay_ms(1); } // 向LCD发送数据 void LCD_Write_Data(unsigned char data) { PORTC |= (1<<LCD_RS); // RS=1 数据模式 PORTC &= ~(1<<LCD_RW); // RW=0 写入 // 发送高4位 PORTA = (PORTA & 0x0F) | (data & 0xF0); PORTC |= (1<<LCD_E); // E=1 delay_ms(1); PORTC &= ~(1<<LCD_E); // E=0 // 发送低4位 PORTA = (PORTA & 0x0F) | ((data << 4) & 0xF0); PORTC |= (1<<LCD_E); // E=1 delay_ms(1); PORTC &= ~(1<<LCD_E); // E=0 delay_ms(1); } // 在LCD上显示字符串 void LCD_Display_String(char *str) { while (*str) { LCD_Write_Data(*str++); } } // 设置LCD光标位置 void LCD_Set_Cursor(uint8_t row, uint8_t col) { uint8_t address; if (row == 0) { address = 0x80 + col; } else { address = 0xC0 + col; } LCD_Write_Command(address); } // 显示时间 void Display_Time() { char buffer[16]; // 第一行显示时间 LCD_Set_Cursor(0, 4); sprintf(buffer, "%02d:%02d:%02d", hour, minute, second); LCD_Display_String(buffer); // 第二行显示日期 LCD_Set_Cursor(1, 4); sprintf(buffer, "20%02d-%02d-%02d", year, month, day); LCD_Display_String(buffer); } // 显示设置模式 void Display_Set_Mode() { char buffer[16]; LCD_Set_Cursor(0, 0); LCD_Display_String("Set:"); switch(set_mode) { case 1: // 设置小时 if(blink_state) { sprintf(buffer, "Hour: %02d", hour); } else { sprintf(buffer, "Hour: "); } break; case 2: // 设置分钟 if(blink_state) { sprintf(buffer, "Minute:%02d", minute); } else { sprintf(buffer, "Minute: "); } break; case 3: // 设置年 if(blink_state) { sprintf(buffer, "Year: 20%02d", year); } else { sprintf(buffer, "Year: "); } break; case 4: // 设置月 if(blink_state) { sprintf(buffer, "Month: %02d", month); } else { sprintf(buffer, "Month: "); } break; case 5: // 设置日 if(blink_state) { sprintf(buffer, "Day: %02d", day); } else { sprintf(buffer, "Day: "); } break; default: sprintf(buffer, "Normal Mode "); } LCD_Set_Cursor(0, 5); LCD_Display_String(buffer); // 仍然显示时间日期 LCD_Set_Cursor(1, 0); sprintf(buffer, "Time:%02d:%02d:%02d", hour, minute, second); LCD_Display_String(buffer); } // 从EEPROM加载时间日期 void Load_Time_From_EEPROM() { hour = eeprom_read_byte((uint8_t*)EEPROM_TIME_HOUR_ADDR); minute = eeprom_read_byte((uint8_t*)EEPROM_TIME_MINUTE_ADDR); year = eeprom_read_byte((uint8_t*)EEPROM_DATE_YEAR_ADDR); month = eeprom_read_byte((uint8_t*)EEPROM_DATE_MONTH_ADDR); day = eeprom_read_byte((uint8_t*)EEPROM_DATE_DAY_ADDR); // 检查读取的值是否有效 if(hour > 23) hour = 0; if(minute > 59) minute = 0; if(year > 99) year = 23; if(month == 0 || month > 12) month = 1; if(day == 0 || day > 31) day = 1; } // 保存时间日期到EEPROM void Save_Time_To_EEPROM() { eeprom_update_byte((uint8_t*)EEPROM_TIME_HOUR_ADDR, hour); eeprom_update_byte((uint8_t*)EEPROM_TIME_MINUTE_ADDR, minute); eeprom_update_byte((uint8_t*)EEPROM_DATE_YEAR_ADDR, year); eeprom_update_byte((uint8_t*)EEPROM_DATE_MONTH_ADDR, month); eeprom_update_byte((uint8_t*)EEPROM_DATE_DAY_ADDR, day); } // 初始化定时器1 (1秒中断) void Timer1_Init() { // 设置定时器1为CTC模式 TCCR1B |= (1 << WGM12); // 设置预分频为1024 TCCR1B |= (1 << CS12) | (1 << CS10); // 设置比较值 (16MHz/1024 = 15625 ticks/sec, 15625 ticks = 1秒) OCR1A = 15625; // 启用比较匹配中断 TIMSK |= (1 << OCIE1A); } // 初始化按键引脚 void Buttons_Init() { // 设置按键引脚为输入,启用上拉电阻 DDRD &= ~((1<<SET_BUTTON) | (1<<ADD_BUTTON) | (1<<SUB_BUTTON)); PORTD |= (1<<SET_BUTTON) | (1<<ADD_BUTTON) | (1<<SUB_BUTTON); } // 按键扫描 void Key_Scan() { static uint8_t last_set_state = 1; static uint8_t last_add_state = 1; static uint8_t last_sub_state = 1; uint8_t current_set_state = PIND & (1<<SET_BUTTON); uint8_t current_add_state = PIND & (1<<ADD_BUTTON); uint8_t current_sub_state = PIND & (1<<SUB_BUTTON); // 检测设置按键按下 if(last_set_state && !current_set_state) { _delay_ms(20); // 消抖 if(!(PIND & (1<<SET_BUTTON))) { set_mode++; if(set_mode > 5) set_mode = 0; if(set_mode == 0) { // 退出设置模式,保存时间到EEPROM Save_Time_To_EEPROM(); } } } // 只在设置模式下检测加减按键 if(set_mode > 0) { // 检测增加按键按下 if(last_add_state && !current_add_state) { _delay_ms(20); // 消抖 if(!(PIND & (1<<ADD_BUTTON))) { switch(set_mode) { case 1: // 增加小时 hour = (hour + 1) % 24; break; case 2: // 增加分钟 minute = (minute + 1) % 60; break; case 3: // 增加年 year = (year + 1) % 100; break; case 4: // 增加月 month = (month % 12) + 1; break; case 5: // 增加日 day = (day % 31) + 1; break; } } } // 检测减少按键按下 if(last_sub_state && !current_sub_state) { _delay_ms(20); // 消抖 if(!(PIND & (1<<SUB_BUTTON))) { switch(set_mode) { case 1: // 减少小时 hour = (hour == 0) ? 23 : hour - 1; break; case 2: // 减少分钟 minute = (minute == 0) ? 59 : minute - 1; break; case 3: // 减少年 year = (year == 0) ? 99 : year - 1; break; case 4: // 减少月 month = (month == 1) ? 12 : month - 1; break; case 5: // 减少日 day = (day == 1) ? 31 : day - 1; break; } } } } last_set_state = current_set_state; last_add_state = current_add_state; last_sub_state = current_sub_state; } // 检查闹钟 void Check_Alarms() { static uint8_t alarm1_triggered = 0; static uint8_t alarm2_triggered = 0; // 检查闹钟1 if(alarm1.enabled && !alarm1_triggered && hour == alarm1.hour && minute == alarm1.minute && second == 0) { alarm1_triggered = 1; PORTB |= (1<<LED_PIN); // 打开LED } // 检查闹钟2 if(alarm2.enabled && !alarm2_triggered && hour == alarm2.hour && minute == alarm2.minute && second == 0) { alarm2_triggered = 1; PORTB |= (1<<LED_PIN); // 打开LED } // 每分钟重置闹钟触发标志 if(second == 0) { alarm1_triggered = 0; alarm2_triggered = 0; } // 如果LED亮起,检测按键关闭 if(PORTB & (1<<LED_PIN)) { if(!(PIND & (1<<SET_BUTTON)) || !(PIND & (1<<ADD_BUTTON)) || !(PIND & (1<<SUB_BUTTON))) { PORTB &= ~(1<<LED_PIN); // 关闭LED } } } // 定时器1比较匹配中断服务程序 ISR(TIMER1_COMPA_vect) { // 更新时间 second++; if(second >= 60) { second = 0; minute++; if(minute >= 60) { minute = 0; hour++; if(hour >= 24) { hour = 0; // 日期增加逻辑 day++; uint8_t max_day = 31; // 处理不同月份的天数 if(month == 4 || month == 6 || month == 9 || month == 11) { max_day = 30; } else if(month == 2) { // 简单处理2月天数(不考虑闰年) max_day = 28; } if(day > max_day) { day = 1; month++; if(month > 12) { month = 1; year++; if(year > 99) year = 0; } } } } } // 更新闪烁状态 (0.5秒周期) timer1_counter++; if(timer1_counter >= 5) { // 10次 = 1秒 (0.1秒中断) timer1_counter = 0; blink_state = !blink_state; } // 检查闹钟 Check_Alarms(); } int main(void) { // 初始化端口 DDRB |= (1<<LED_PIN); // LED引脚为输出 PORTB &= ~(1<<LED_PIN); // 初始关闭LED // 初始化按键 Buttons_Init(); // 初始化LCD LCD_Init(); // 从EEPROM加载时间 Load_Time_From_EEPROM(); // 初始化定时器 Timer1_Init(); // 启用全局中断 sei(); // 清屏并显示欢迎信息 LCD_Write_Command(0x01); LCD_Set_Cursor(0, 3); LCD_Display_String("AVR Clock"); LCD_Set_Cursor(1, 2); LCD_Display_String("Initializing..."); delay_ms(1000); LCD_Write_Command(0x01); while(1) { // 扫描按键 Key_Scan(); // 更新显示 if(set_mode == 0) { Display_Time(); } else { Display_Set_Mode(); } // 短暂延迟 delay_ms(100); } return 0; }

我现在有一个buck电路和一个已经烧录了buck稳压程序的P4板子和一个学生电源和一根高品质SMA公母转换天线延展线(RG316适用SMA-JK连接)和一个OLED屏,我要怎么接线,给多大电压,才能使OLED屏显示PA4口(ADC电压采样口)所接收到的电压下面是我的代码#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" float pid_out; volatile uint8_t adc_data_ready = 0; volatile uint8_t tim_update_flag ; volatile uint32_t last_adc_value = 0; float Vout_actual = 0.0f; float Target = 20.0f; // 目标输出电压 float voltage1; // 全局PID控制器 PID_Controller pid; extern __IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]; extern uint16_t TIM1_Impluse ;//高级定时器占空比 int main(void) { OLED_Init(); Adc_Init(); 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 (adc_data_ready) { // 计算电压 voltage1 = last_adc_value * 3.3f*0.000244140625; Vout_actual = voltage1; adc_data_ready = 0; } if (tim_update_flag) { // 使用PID计算 pid_out = pid_control(&pid, Target, Vout_actual); // 安全更新PWM (限制在0-8400) TIM1_Impluse = pid_out * 84; // 0-100% -> 0-8400 TIM1->CCR1 = TIM1_Impluse; // // 重置标志 tim_update_flag = 0; } // a=pid_control (5 , 0.25, 0 ,Target ,Vout_actual); // ADC_Read(); // float six = 6; // char str[40]; // sprintf(str,"Vout_actual = %.3f",Vout_actual); // OLED_ShowString(WORD_WIDTH*0,WORD_HIGH*1,(u8 *)str,WORD_SIZE); // OLED_Refresh_Gram(); // delay_us(100); static char display_buffer[2][40]; snprintf(display_buffer[0], 40, "Vout: %.2fV", Vout_actual); delay_ms(50); 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(); } } #include "stm32f4xx_it.h" #include "oled.h" #include <math.h> #include "./adc/bsp_adc.h" #include "pid.h" extern uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]; extern float voltage1; extern float pid_out; extern float Vout_actual; 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; void TIM1_UP_TIM10_IRQHandler(void) { if(TIM_GetITStatus(TIM1,TIM_IT_Update) == SET) { // Vout_actual = voltage1; // pid_out = pid_control (5 , 0.25, 0 ,Vout_set ,Vout_actual); // TIM1->CCR1 = pid_out; // tim_update_flag = 1; // 设置标志,表示发生了一次更新中断 TIM_ClearITPendingBit(TIM1, TIM_IT_Update); } } void DMA2_Stream0_IRQHandler(void) { // 处理传输完成中断 if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)) { DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); last_adc_value = ADC_ConvertedValue[0]; adc_data_ready = 1; } // 处理半传输中断 if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0)) { DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0); } // 处理传输错误中断 if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TEIF0)) { DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TEIF0); // 这里可以添加错误处理代码 } } 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; //PWM1和2中的CH和CCR之间值的大小(多用pwm1的模式1) TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High; //当使用了刹车功能时,两路PWM1和2都会被强制禁止,进而输出我们配置的的空闲先状态 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=2; 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 "oled.h" #include "oledfont.h" #include "delay.h" //OLED的显存 //存放格式如下. //[0]0 1 2 3 ... 127 //[1]0 1 2 3 ... 127 //[2]0 1 2 3 ... 127 //[3]0 1 2 3 ... 127 //[4]0 1 2 3 ... 127 //[5]0 1 2 3 ... 127 //[6]0 1 2 3 ... 127 //[7]0 1 2 3 ... 127 u8 OLED_GRAM[128][8]; #if OLED_MODE==0 //向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { u8 i; OLED_DC=cmd; OLED_CS=0; for(i=0;i<8;i++) { OLED_SCL=0; if(dat&0x80) OLED_SDA=1; else OLED_SDA=0; OLED_SCL=1; dat<<=1; } OLED_CS=1; OLED_DC=1; } #endif #if OLED_MODE==1 //向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { OLED_DATA_OUT(dat); OLED_RST=cmd; OLED_CS=0; OLED_WR=0; OLED_WR=1; OLED_CS=1; OLED_DC=1; } #endif #if OLED_MODE==2 void OLED_WR_Byte(u8 dat,u8 cmd) { } #endif //更新显存到LCD void OLED_Refresh_Gram(void) { u8 i,n; for(i=0;i<8;i++) { OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7) OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址 OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址 for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); } } void OLED_Set_Pos(unsigned char x, unsigned char y) { OLED_WR_Byte(0xb0+y,OLED_CMD); OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD); OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD); } //开启OLED显示 void OLED_Display_On(void) { OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令 OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON } //关闭OLED显示 void OLED_Display_Off(void) { OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令 OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF } //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!! void OLED_Clear(void) { u8 i,n; for(i=0;i<8;i++) { for(n=0;n<128;n++) { OLED_GRAM[n][i]=0; } } OLED_Refresh_Gram();//更新显示 } //画点 //x:0~127 //y:0~63 //t:1 填充 0,清空 void OLED_DrawPoint(u8 x,u8 y,u8 t) { u8 pos,bx,temp=0; if(x>127||y>63)return;//超出范围了. pos=7-y/8; bx=y%8; temp=1<<(7-bx); if(t)OLED_GRAM[x][pos]|=temp; else OLED_GRAM[x][pos]&=~temp; } void OLED_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2) { u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=y1; if(delta_x>0)incx=1; //设置单步方向 else if(delta_x==0)incx=0;//垂直线 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y==0)incy=0;//水平线 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<=distance+1;t++ )//画线输出 { OLED_DrawPoint(uRow,uCol,1);//画点 xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } void OLED_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2) { OLED_DrawLine(x1,y1,x2,y1); OLED_DrawLine(x1,y1,x1,y2); OLED_DrawLine(x1,y2,x2,y2); OLED_DrawLine(x2,y1,x2,y2); } //x1,y1,x2,y2 填充区域的对角坐标 //确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63 //dot:0,清空;1,填充 void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot) { u8 x,y; for(x=x1;x<=x2;x++) { for(y=y1;y<=y2;y++) { OLED_DrawPoint(x,y,dot); } } OLED_Refresh_Gram();//更新显示 } //在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~63 //mode:0,反白显示;1,正常显示 //size:选择字体 12/16/24 void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0)) * (size/2); //得到字体一个字符对应点阵集所占的字节数 chr=chr-' ';//得到偏移后的值 for(t=0;t<csize;t++) { if(size==12)temp=ascii_1206[chr][t]; //调用1206字体 else if(size==16)temp=ascii_1608[chr][t]; //调用1608字体 else if(size==24)temp=ascii_2412[chr][t]; //调用2412字体 else return; //没有的字库 for(t1=0;t1<8;t1++) { if(temp&0x80)OLED_DrawPoint(x,y,mode); else OLED_DrawPoint(x,y,!mode); temp<<=1; y++; if((y-y0)==size) { y=y0; x++; break; } } } } //m^n函数 u32 oled_pow(u8 m,u8 n) { u32 result=1; while(n--)result*=m; return result; } //显示2个数字 //x,y :起点坐标 //len :数字的位数 //size:字体大小 //num:数值(0~4294967295); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size) { u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/oled_pow(10,len-t-1))%10; if(enshow==0&&t<(len-1)) { if(temp==0) { OLED_ShowChar(x+(size/2)*t,y,' ',size,1); continue; }else enshow=1; } OLED_ShowChar(x+(size/2)*t,y,temp+'0',size,1); } } //显示字符串 //x,y:起点坐标 //size:字体大小 //*p:字符串起始地址 void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size) { while((*p<='~')&&(*p>=' '))//判断是不是非法字符! { if(x>(128-(size/2))){x=0;y+=size;} if(y>(64-size)){y=x=0;OLED_Clear();} OLED_ShowChar(x,y,*p,size,1); x+=size/2; p++; } } //显示汉字 //x,y:起点坐标 //pos:数组位置汉字显示 //size:字体大小 //mode:0,反白显示;1,正常显示 void OLED_ShowFontHZ(u8 x,u8 y,u8 pos,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0))*(size);//得到字体一个字符对应点阵集所占的字节数 if(size!=12&&size!=16&&size!=24&&size!=32)return; //不支持的size for(t=0;t<csize;t++) { if(size==12)temp=FontHzk_12[pos][t]; //调用1206字体 else if(size==16)temp=FontHzk_16[pos][t]; //调用1608字体 else if(size==24)temp=FontHzk_24[pos][t]; //调用2412字体 else if(size==32)temp=FontHzk_32[pos][t]; //调用3216字体 else return; //没有的字库 for(t1=0;t1<8;t1++) { if(temp&0x80)OLED_DrawPoint(x,y,mode); else OLED_DrawPoint(x,y,!mode); temp<<=1; y++; if((y-y0)==size) { y=y0; x++; break; } } } } //显示BMP图片128×64 //起始点坐标(x,y),x的范围0~127,y为页的范围0~7 void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]) { u16 j=0; u8 x,y; if(y1%8==0)y=y1/8; else y=y1/8+1; for(y=y0;y<y1;y++) { OLED_Set_Pos(x0,y); for(x=x0;x<x1;x++) { OLED_WR_Byte(BMP[j++],OLED_DATA); } } } //GND 接电源地 //VCC 接5V或3.3v电源 //D0 接PD6(SCL) //D1 接PD7(SDA) //RES 接PD4 //DC 接PD5 //CS 接PD3 void OLED_Init() { GPIO_InitTypeDef GPIO_InitStructure; #if OLED_MODE==0 //4线SPI模式 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_6;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不拉 GPIO_Init(GPIOE,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOE,GPIO_Pin_2|GPIO_Pin_6); //拉高电平 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不拉 GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13); //拉高电平 OLED_Clear(); #endif #if OLED_MODE==1 //8080模式 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOC,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOD,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOD,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); GPIO_InitStructure.GPIO_Pin = 0XFF; //PC0-7 GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC,0xFF); //PC0-7输出高 #endif #if OLED_MODE==2 //IIC模式 #endif OLED_RST=1; delay_ms(100); OLED_RST=0; delay_ms(100); OLED_RST=1; OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示 OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率 OLED_WR_Byte(80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率 OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数 OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64) OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移 OLED_WR_Byte(0X00,OLED_CMD); //默认为0 OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数. OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置 OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭 OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式 OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10; OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127; OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数 OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置 OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置 OLED_WR_Byte(0x81,OLED_CMD); //对比度设置 OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮) OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期 OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2; OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率 OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc; OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏) OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示 OLED_WR_Byte(0xAF,OLED_CMD); //开启显示 OLED_Clear(); } #ifndef _oled_H #define _oled_H #include "sys/system.h" #include "stdlib.h" #define WORD_SIZE 12 #define X_OFFSET_WORD 0 #define Y_OFFSET_WORD 0 #define X_OFFSTE_PIXEL 0 #define Y_OFFSTE_PIXEL 0 #if WORD_SIZE != 12 && WORD_SIZE != 16 && WORD_SIZE != 24 #define WORD_SIZE 12 #endif #if WORD_SIZE == 24 #define WORD_WIDTH 12 #define WORD_HIGH 24 #endif #if WORD_SIZE == 16 #define WORD_WIDTH 8 #define WORD_HIGH 16 #endif #if WORD_SIZE == 12 #define WORD_WIDTH 6 #define WORD_HIGH 12 #endif //OLED模式设置 //0:4线串行SPI模式 //1:并行8080模式 //2:IIC模式 #define OLED_MODE 0 #define SIZE 16 #define XLevelL 0x00 #define XLevelH 0x10 #define Max_Column 128 #define Max_Row 64 #define Brightness 0xFF #define X_WIDTH 128 #define Y_WIDTH 64 #if OLED_MODE==0 //OLDE-SPI4线控制管脚定义 #define OLED_SCL PCout(1) #define OLED_SDA PCout(0) #define OLED_RST PCout(13) #define OLED_DC PEout(6) #define OLED_CS PEout(2) #endif #if OLED_MODE==1 //OLDE-8080总线控制管脚定义 #define OLED_CS PDout(3) #define OLED_RST PDout(4) #define OLED_DC PDout(5) #define OLED_WR PDout(6) #define OLED_RD PDout(7) #define OLED_DATA_OUT(x) GPIO_Write(GPIOC,x);//输出 #endif #if OLED_MODE==2 //OLDE-IIC总线控制管脚定义 #endif #define OLED_CMD 0 //写命令 #define OLED_DATA 1 //写数据 //OLED控制用函数 void OLED_WR_Byte(u8 dat,u8 cmd); void OLED_Display_On(void); void OLED_Display_Off(void); void OLED_Set_Pos(unsigned char x, unsigned char y); void OLED_Init(void); void OLED_Refresh_Gram(void); void OLED_Clear(void); void OLED_DrawPoint(u8 x,u8 y,u8 t); void OLED_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2); void OLED_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2); void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot); void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size); void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size); void OLED_ShowFontHZ(u8 x,u8 y,u8 pos,u8 size,u8 mode); void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]); #endif #include "./adc/bsp_adc.h" __IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]={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_PeripheralBaseAddr = (u32)ADC_ConvertedValue ; // ADC 数据寄存器地址 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADC_ConvertedValue; // 内存缓冲区地址 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 = ENABLE; // 扫描模式使能 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_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 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 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); #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; } #ifndef __PID_H_ #define __PID_H_ typedef struct { float kp, ki, kd; float integral; float prev_error; float max_output; float min_output; } PID_Controller; float pid_control(PID_Controller* pid, float setpoint, float input); #endif

下面这个buck闭环电路程序的oled屏亮不亮,下面是这个函数的代码#include "stm32f4xx.h" #include "./usart/bsp_usart.h" #include "delay.h" #include "sys.h" #include "PID.h" #include "math.h" #include "./adc/bsp_adc.h" #include "tim.h" #include "oled.h" #include "stdio.h" #include "stdlib.h" extern float voltage1, voltage2, voltage3; extern float Vout_actual; float Target= 25; // 目标输出电压25 float a; //extern __IO uint16_t ADC_ConvertedValue; extern uint16_t TIM_Advance_Impulse; int main(void) { OLED_Init(); // 首先初始化OLED TIM_Init(); PID_init(); Adc_Init(); while(1) { ADC_Read(); a= PID_DC( Target ,Vout_actual, 20.0f ); float six = 6; char str[40]; sprintf(str,"Vout_actual = %.3f",Vout_actual); OLED_ShowString(WORD_WIDTH*0,WORD_HIGH*1,(u8 *)str,WORD_SIZE); OLED_Refresh_Gram(); delay_us(100); sprintf(str,"six = %.3f",six); OLED_ShowString(WORD_WIDTH*0,WORD_HIGH*1,(u8 *)str,WORD_SIZE); OLED_Refresh_Gram(); delay_us(100); } } /*********************************************END OF FILE**********************/ pid文件:#include "stdio.h" #include "sys.h" #include "PID.h" //extern float V0,V1,V2; float duty=0; float pid_out=0; struct _pid { float SetSpeed; //定义设定值 float ActualSpeed; //定义实际值 float err; //定义偏差值 float err_last; //定义上一个偏差值 float Kp, Ki, Kd; //定义比例、积分、微分系数 float voltage; //定义电压值(控制执行器的变量) float integral; //定义积分值 float S; //返回值 }pid; void PID_init() { pid.SetSpeed = 0.0; pid.ActualSpeed = 0.0; pid.err = 0.0; pid.err_last = 0.0; pid.voltage = 0.0; pid.integral = 0.0; pid.Kp = 150; pid.Ki = 0.55; pid.Kd = 0; } float PID_realize(float speed, float Actual) { pid.SetSpeed = speed; //目标值 pid.ActualSpeed = Actual; //实际值 pid.err = pid.SetSpeed - pid.ActualSpeed; //误差 pid.integral += pid.err; //积分项误差相加 pid.voltage = pid.Kp * pid.err + pid.Ki * pid.integral + pid.Kd * (pid.err - pid.err_last); //计算结果 0.2*27+0.1* pid.err_last = pid.err; //更新误差 pid.S = pid.voltage * 1.0f; //计算结果 返回值 return pid.S; } float PID_DC( float goal ,float Actual,float k ) { Actual=Actual*k; pid_out = PID_realize(goal, Actual); duty+=pid_out; if(duty>=4200) duty=4200; if(duty<=-4200) duty=0; TIM_SetCompare1(TIM8,4200+duty) ; return pid_out; } pid.h #ifndef __PID_H #define __PID_H void PID_init(void);//PID参数初始化 float PID_realize(float speed, float Actual);//实现PID算法 float PID_DC( float goal ,float Actual,float k ); #endif adc模块:#include "./adc/bsp_adc.h" __IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]={0}; float voltage1=0, voltage2=0, voltage3=0; float Vout_actual; 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); /*=====================通道2======================*/ // 使能 GPIO 时钟 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK2,ENABLE); // 配置 IO GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //不上拉不下拉 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADC_GPIO_PORT2, &GPIO_InitStructure); /*=====================通道3=======================*/ // 使能 GPIO 时钟 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK3,ENABLE); // 配置 IO GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //不上拉不下拉 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADC_GPIO_PORT3, &GPIO_InitStructure); } static void ADC_Mode_Config(void) { DMA_InitTypeDef DMA_InitStructure; ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; // ------------------DMA Init 结构体参数 初始化-------------------------- // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的 // 开启DMA时钟 RCC_AHB1PeriphClockCmd(ADC_DMA_CLK, ENABLE); // 外设基址为:ADC 数据寄存器地址 DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_DR_ADDR; // 存储器地址,实际上就是一个内部SRAM的变量 DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_ConvertedValue; // 数据传输方向为外设到存储器 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; // 存储器数据大小也为半字,跟外设数据大小相同 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 循环传输模式 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响 DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 禁止DMA FIFO ,使用直连模式 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // FIFO 大小,FIFO模式禁止时,这个不用配置 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // 选择 DMA 通道,通道存在于流中 DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL; //初始化DMA流,流相当于一个大的管道,管道里面有很多通道 DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure); // 使能DMA传输完成中断 DMA_ITConfig(ADC_DMA_STREAM, DMA_IT_TC, ENABLE); // 使能DMA流 DMA_Cmd(ADC_DMA_STREAM, ENABLE); // 开启ADC时钟 RCC_APB2PeriphClockCmd(ADC_CLK , ENABLE); // -------------------ADC Common 结构体 参数 初始化------------------------ // 独立ADC模式 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; // 时钟为fpclk x分频 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; // 禁止DMA直接访问模式 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; // 采样时间间隔 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; ADC_CommonInit(&ADC_CommonInitStructure); // -------------------ADC Init 结构体 参数 初始化-------------------------- ADC_StructInit(&ADC_InitStructure); // ADC 分辨率 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; // 扫描模式,多通道采集需要 ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 连续转换 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; //转换通道 1个 ADC_InitStructure.ADC_NbrOfConversion = RHEOSTAT_NOFCHANEL; ADC_Init(ADC_, &ADC_InitStructure); //--------------------------------------------------------------------------- // 配置 ADC 通道转换顺序和采样时间周期 ADC_RegularChannelConfig(ADC_, ADC_CHANNEL1, 1, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC_, ADC_CHANNEL2, 2, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC_, ADC_CHANNEL3, 3, ADC_SampleTime_15Cycles); // 使能DMA请求 after last transfer (Single-ADC mode) ADC_DMARequestAfterLastTransferCmd(ADC_, ENABLE); // 使能ADC DMA ADC_DMACmd(ADC_, ENABLE); // 使能ADC ADC_Cmd(ADC_, ENABLE); //开始adc转换,软件触发 ADC_SoftwareStartConv(ADC_); } static void ADC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //配置DMA 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_Read(void) { voltage1=(float)ADC_ConvertedValue[0]*0.000244140625*3.3; voltage2=(float)ADC_ConvertedValue[1]*0.000244140625*3.3; voltage3=(float)ADC_ConvertedValue[2]*0.000244140625*3.3; Vout_actual = voltage1; } void Adc_Init(void) { ADC_GPIO_Config(); ADC_Mode_Config(); ADC_NVIC_Config(); } adc.h #ifndef __BSP_ADC_H #define __BSP_ADC_H #include "stm32f4xx.h" #define RHEOSTAT_NOFCHANEL 3 /*=====================通道1 IO======================*/ // ADC IO宏定义 #define ADC_GPIO_PORT1 GPIOA #define ADC_GPIO_PIN1 GPIO_Pin_1 #define ADC_GPIO_CLK1 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL1 ADC_Channel_1 /*=====================通道2 IO ======================*/ // ADC IO宏定义 #define ADC_GPIO_PORT2 GPIOA #define ADC_GPIO_PIN2 GPIO_Pin_2 #define ADC_GPIO_CLK2 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL2 ADC_Channel_2 /*=====================通道3 IO ======================*/ // ADC IO宏定义 #define ADC_GPIO_PORT3 GPIOA #define ADC_GPIO_PIN3 GPIO_Pin_3 #define ADC_GPIO_CLK3 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL3 ADC_Channel_3 // ADC 序号宏定义 #define ADC_ ADC1 #define ADC_CLK RCC_APB2Periph_ADC1 // ADC DR寄存器宏定义,ADC转换后的数字值则存放在这里 #define RHEOSTAT_ADC_DR_ADDR ((u32)ADC1+0x4c) // ADC 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); void ADC_Read(void); #endif /* __BSP_ADC_H */ tim文件 #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; //PWM1和2中的CH和CCR之间值的大小(多用pwm1的模式1) TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High; //当使用了刹车功能时,两路PWM1和2都会被强制禁止,进而输出我们配置的的空闲先状态 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_0); //分组 NVIC_InitStructure.NVIC_IRQChannel=TIM1_UP_TIM10_IRQn; //定时器1中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; 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(); } tim.h #ifndef __TIM_H #define __TIM_H #include "sys.h" void TIM_Init(void); #endif oled模块: #include "oled.h" #include "oledfont.h" #include "delay.h" //OLED的显存 //存放格式如下. //[0]0 1 2 3 ... 127 //[1]0 1 2 3 ... 127 //[2]0 1 2 3 ... 127 //[3]0 1 2 3 ... 127 //[4]0 1 2 3 ... 127 //[5]0 1 2 3 ... 127 //[6]0 1 2 3 ... 127 //[7]0 1 2 3 ... 127 u8 OLED_GRAM[128][8]; #if OLED_MODE==0 //向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { u8 i; OLED_DC=cmd; OLED_CS=0; for(i=0;i<8;i++) { OLED_SCL=0; if(dat&0x80) OLED_SDA=1; else OLED_SDA=0; OLED_SCL=1; dat<<=1; } OLED_CS=1; OLED_DC=1; } #endif #if OLED_MODE==1 //向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { OLED_DATA_OUT(dat); OLED_RST=cmd; OLED_CS=0; OLED_WR=0; OLED_WR=1; OLED_CS=1; OLED_DC=1; } #endif #if OLED_MODE==2 void OLED_WR_Byte(u8 dat,u8 cmd) { } #endif //更新显存到LCD void OLED_Refresh_Gram(void) { u8 i,n; for(i=0;i<8;i++) { OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7) OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址 OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址 for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); } } void OLED_Set_Pos(unsigned char x, unsigned char y) { OLED_WR_Byte(0xb0+y,OLED_CMD); OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD); OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD); } //开启OLED显示 void OLED_Display_On(void) { OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令 OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON } //关闭OLED显示 void OLED_Display_Off(void) { OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令 OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF } //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!! void OLED_Clear(void) { u8 i,n; for(i=0;i<8;i++) { for(n=0;n<128;n++) { OLED_GRAM[n][i]=0; } } OLED_Refresh_Gram();//更新显示 } //画点 //x:0~127 //y:0~63 //t:1 填充 0,清空 void OLED_DrawPoint(u8 x,u8 y,u8 t) { u8 pos,bx,temp=0; if(x>127||y>63)return;//超出范围了. pos=7-y/8; bx=y%8; temp=1<<(7-bx); if(t)OLED_GRAM[x][pos]|=temp; else OLED_GRAM[x][pos]&=~temp; } void OLED_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2) { u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=y1; if(delta_x>0)incx=1; //设置单步方向 else if(delta_x==0)incx=0;//垂直线 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y==0)incy=0;//水平线 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<=distance+1;t++ )//画线输出 { OLED_DrawPoint(uRow,uCol,1);//画点 xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } void OLED_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2) { OLED_DrawLine(x1,y1,x2,y1); OLED_DrawLine(x1,y1,x1,y2); OLED_DrawLine(x1,y2,x2,y2); OLED_DrawLine(x2,y1,x2,y2); } //x1,y1,x2,y2 填充区域的对角坐标 //确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63 //dot:0,清空;1,填充 void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot) { u8 x,y; for(x=x1;x<=x2;x++) { for(y=y1;y<=y2;y++) { OLED_DrawPoint(x,y,dot); } } OLED_Refresh_Gram();//更新显示 } //在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~63 //mode:0,反白显示;1,正常显示 //size:选择字体 12/16/24 void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0)) * (size/2); //得到字体一个字符对应点阵集所占的字节数 chr=chr-' ';//得到偏移后的值 for(t=0;t<csize;t++) { if(size==12)temp=ascii_1206[chr][t]; //调用1206字体 else if(size==16)temp=ascii_1608[chr][t]; //调用1608字体 else if(size==24)temp=ascii_2412[chr][t]; //调用2412字体 else return; //没有的字库 for(t1=0;t1<8;t1++) { if(temp&0x80)OLED_DrawPoint(x,y,mode); else OLED_DrawPoint(x,y,!mode); temp<<=1; y++; if((y-y0)==size) { y=y0; x++; break; } } } } //m^n函数 u32 oled_pow(u8 m,u8 n) { u32 result=1; while(n--)result*=m; return result; } //显示2个数字 //x,y :起点坐标 //len :数字的位数 //size:字体大小 //num:数值(0~4294967295); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size) { u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/oled_pow(10,len-t-1))%10; if(enshow==0&&t<(len-1)) { if(temp==0) { OLED_ShowChar(x+(size/2)*t,y,' ',size,1); continue; }else enshow=1; } OLED_ShowChar(x+(size/2)*t,y,temp+'0',size,1); } } //显示字符串 //x,y:起点坐标 //size:字体大小 //*p:字符串起始地址 void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size) { while((*p<='~')&&(*p>=' '))//判断是不是非法字符! { if(x>(128-(size/2))){x=0;y+=size;} if(y>(64-size)){y=x=0;OLED_Clear();} OLED_ShowChar(x,y,*p,size,1); x+=size/2; p++; } } //显示汉字 //x,y:起点坐标 //pos:数组位置汉字显示 //size:字体大小 //mode:0,反白显示;1,正常显示 void OLED_ShowFontHZ(u8 x,u8 y,u8 pos,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0))*(size);//得到字体一个字符对应点阵集所占的字节数 if(size!=12&&size!=16&&size!=24&&size!=32)return; //不支持的size for(t=0;t<csize;t++) { if(size==12)temp=FontHzk_12[pos][t]; //调用1206字体 else if(size==16)temp=FontHzk_16[pos][t]; //调用1608字体 else if(size==24)temp=FontHzk_24[pos][t]; //调用2412字体 else if(size==32)temp=FontHzk_32[pos][t]; //调用3216字体 else return; //没有的字库 for(t1=0;t1<8;t1++) { if(temp&0x80)OLED_DrawPoint(x,y,mode); else OLED_DrawPoint(x,y,!mode); temp<<=1; y++; if((y-y0)==size) { y=y0; x++; break; } } } } //显示BMP图片128×64 //起始点坐标(x,y),x的范围0~127,y为页的范围0~7 void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]) { u16 j=0; u8 x,y; if(y1%8==0)y=y1/8; else y=y1/8+1; for(y=y0;y<y1;y++) { OLED_Set_Pos(x0,y); for(x=x0;x<x1;x++) { OLED_WR_Byte(BMP[j++],OLED_DATA); } } } //GND 接电源地 //VCC 接5V或3.3v电源 //D0 接PD6(SCL) //D1 接PD7(SDA) //RES 接PD4 //DC 接PD5 //CS 接PD3 void OLED_Init() { GPIO_InitTypeDef GPIO_InitStructure; #if OLED_MODE==0 //4线SPI模式 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_6;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不拉 GPIO_Init(GPIOE,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOE,GPIO_Pin_2|GPIO_Pin_6); //拉高电平 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不拉 GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13); //拉高电平 OLED_Clear(); #endif #if OLED_MODE==1 //8080模式 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOC,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOD,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOD,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); GPIO_InitStructure.GPIO_Pin = 0XFF; //PC0-7 GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC,0xFF); //PC0-7输出高 #endif #if OLED_MODE==2 //IIC模式 #endif OLED_RST=1; delay_ms(100); OLED_RST=0; delay_ms(100); OLED_RST=1; OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示 OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率 OLED_WR_Byte(80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率 OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数 OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64) OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移 OLED_WR_Byte(0X00,OLED_CMD); //默认为0 OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数. OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置 OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭 OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式 OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10; OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127; OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数 OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置 OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置 OLED_WR_Byte(0x81,OLED_CMD); //对比度设置 OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮) OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期 OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2; OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率 OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc; OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏) OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示 OLED_WR_Byte(0xAF,OLED_CMD); //开启显示 OLED_Clear(); } oled.h #ifndef _oled_H #define _oled_H #include "sys/system.h" #include "stdlib.h" #define WORD_SIZE 12 #define X_OFFSET_WORD 0 #define Y_OFFSET_WORD 0 #define X_OFFSTE_PIXEL 0 #define Y_OFFSTE_PIXEL 0 #if WORD_SIZE != 12 && WORD_SIZE != 16 && WORD_SIZE != 24 #define WORD_SIZE 12 #endif #if WORD_SIZE == 24 #define WORD_WIDTH 12 #define WORD_HIGH 24 #endif #if WORD_SIZE == 16 #define WORD_WIDTH 8 #define WORD_HIGH 16 #endif #if WORD_SIZE == 12 #define WORD_WIDTH 6 #define WORD_HIGH 12 #endif //OLED模式设置 //0:4线串行SPI模式 //1:并行8080模式 //2:IIC模式 #define OLED_MODE 0 #define SIZE 16 #define XLevelL 0x00 #define XLevelH 0x10 #define Max_Column 128 #define Max_Row 64 #define Brightness 0xFF #define X_WIDTH 128 #define Y_WIDTH 64 #if OLED_MODE==0 //OLDE-SPI4线控制管脚定义 #define OLED_SCL PCout(1) #define OLED_SDA PCout(0) #define OLED_RST PCout(13) #define OLED_DC PEout(6) #define OLED_CS PEout(2) #endif #if OLED_MODE==1 //OLDE-8080总线控制管脚定义 #define OLED_CS PDout(3) #define OLED_RST PDout(4) #define OLED_DC PDout(5) #define OLED_WR PDout(6) #define OLED_RD PDout(7) #define OLED_DATA_OUT(x) GPIO_Write(GPIOC,x);//输出 #endif #if OLED_MODE==2 //OLDE-IIC总线控制管脚定义 #endif #define OLED_CMD 0 //写命令 #define OLED_DATA 1 //写数据 //OLED控制用函数 void OLED_WR_Byte(u8 dat,u8 cmd); void OLED_Display_On(void); void OLED_Display_Off(void); void OLED_Set_Pos(unsigned char x, unsigned char y); void OLED_Init(void); void OLED_Refresh_Gram(void); void OLED_Clear(void); void OLED_DrawPoint(u8 x,u8 y,u8 t); void OLED_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2); void OLED_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2); void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot); void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size); void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size); void OLED_ShowFontHZ(u8 x,u8 y,u8 pos,u8 size,u8 mode); void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]); #endif stm32f4xx_it.c中断文件:/* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_it.h" #include "./usart/bsp_usart.h" #include "./adc/bsp_adc.h" #include "PID.h" /** @addtogroup STM32F429I_DISCOVERY_Examples * @{ */ /** @addtogroup FMC_SDRAM * @{ */ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /******************************************************************************/ /* Cortex-M4 Processor Exceptions Handlers */ /******************************************************************************/ /** * @brief This function handles NMI exception. * @param None * @retval None */ extern uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]; uint16_t TIM_Advance_Impulse ;//高级定时器占空比 extern float Vout_actual; float Vout_set; // 目标输出电压 extern float pid_out; void TIM1_UP_IRQHandler(void) { if(TIM_GetITStatus(TIM1,TIM_IT_Update) == SET) { pid_out = PID_DC(Vout_set, Vout_actual, 20.0f); TIM1->CCR1 = pid_out; TIM_ClearITPendingBit(TIM1, TIM_IT_Update); } } void DMA2_Stream0_IRQHandler(void) { // 检查传输完成中断标志 if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) != RESET) { // 清除中断标志 DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); // 调用ADC_Read计算电压 ADC_Read(); } } //void ADC_IRQHandler(void) //{ // if(ADC_GetITStatus(ADC_,ADC_IT_EOC) == SET) // { // ADC_ConvertedValue = ADC_GetConversionValue(ADC_); // } // ADC_ClearITPendingBit(ADC_,ADC_IT_EOC); //} // void NMI_Handler(void) { } /** * @brief This function handles Hard Fault exception. * @param None * @retval None */ void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ while (1) {} } /** * @brief This function handles Memory Manage exception. * @param None * @retval None */ void MemManage_Handler(void) { /* Go to infinite loop when Memory Manage exception occurs */ while (1) {} } /** * @brief This function handles Bus Fault exception. * @param None * @retval None */ void BusFault_Handler(void) { /* Go to infinite loop when Bus Fault exception occurs */ while (1) {} } /** * @brief This function handles Usage Fault exception. * @param None * @retval None */ void UsageFault_Handler(void) { /* Go to infinite loop when Usage Fault exception occurs */ while (1) {} } /** * @brief This function handles Debug Monitor exception. * @param None * @retval None */ void DebugMon_Handler(void) {} /** * @brief This function handles SVCall exception. * @param None * @retval None */ void SVC_Handler(void) {} /** * @brief This function handles PendSV_Handler exception. * @param None * @retval None */ void PendSV_Handler(void) {} /** * @brief This function handles SysTick Handler. * @param None * @retval None */ void SysTick_Handler(void) {} /******************************************************************************/ /* STM32F4xx Peripherals Interrupt Handlers */ /* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ /* available peripheral interrupt handler's name please refer to the startup */ /* file (startup_stm32f429_439xx.s). */ /******************************************************************************/ void DEBUG_USART_IRQHandler(void) { uint8_t ucTemp; if(USART_GetITStatus(DEBUG_USART,USART_IT_RXNE)!=RESET) { ucTemp = USART_ReceiveData( DEBUG_USART ); USART_SendData(DEBUG_USART,ucTemp); } USART_ClearITPendingBit(USART1,USART_IT_IDLE); } //void ADVANCE_TIM_IRQHandler(void) //{ // if(TIM_GetITStatus(ADVANCE_TIM,TIM_IT_Update)==SET) //溢出中断 // { // Get_AUTO_RST_Mode_Data(value,8); //自动扫描模式,自动扫描并转换8通道。转换数据存与Value数组中 // printf("\r\n试一试\r\n"); // } // TIM_ClearITPendingBit(ADVANCE_TIM,TIM_IT_Update); //清除中断标志位 //} /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

大家在看

recommend-type

doPDF10软件,pdf虚拟打印机

doPDF10,pdf虚拟打印机,word,cad转pdf,虚拟打印转格式
recommend-type

服务器选项与性能估算.pdf

系统部署方案 - 2 - 前 言 1 系统部署方式 1.1 标准方案 现在 IT 的发展趋势是数据集中,数据集中的核心是对服务器进行整合。特 别是一些大型企业,建立企业数据中心,购买高性能的主机,对数据集中管理, 已成为一种潮流。金蝶 EAS 服务器的部署方式推荐集中式。 金蝶 EAS 支持多层架构,客户端既可通过 TCP 连接服务器,也可以通过 标准的 HTTP 协议连接服务器。应用服务器与数据库服务器可以物理上安装在 一台服务器上,基于性能考虑,一般是分开在两台不同的硬件服务器上,也可 以安装在多台服务器集群之中。 1.2 双机互备方案 采用双机互备的部署方式,主要是解决系统的可靠性问题,其中一台服务器出 现故障,另一台就承担应用服务器和数据库服务器的全部任务。 - 3 - 应用服务器与数据服务器通过心跳线连接,互为备份。 1.3 应用级集群部署方案 应用服务器集群主要是解决在大规模并发处理情况下单机以及单实例的性能瓶 颈问题,以及满足客户对系统高可靠性的要求,EAS 实现了一种应用服务器无 关的高可用集群。 由于数据库服务器的集群是采用 Oracle 或 DB2 的系统集群技 术
recommend-type

KISSsoft全实例中文教程

本教程一共361页,是一本十分完整的教程。同时其内容也非常丰富,包含各种齿轮的分析计算方法以及出各种数据报告等等。KISSsoft是一款专业的齿轮分析软件,对需要的人有极大帮助!
recommend-type

开心小闹钟 V2.8 Beta 3 注册版

开心小闹钟 V2.8 Beta 3 注册版 个人觉得这款电脑闹钟是我用过最好的一个闹钟软件 最牛X的是你可以任意修改它的界面 已经注册好了 不用麻烦了
recommend-type

ipmitool v1.8.18 for windows

服务器BMC访问控制工具,windows版,自己编译的,用着还不错。基于github最新版1.8.18编译。

最新推荐

recommend-type

电力电子领域Boost单闭环仿真模型对电压阶跃变化与负载突变的稳定控制研究 电力电子 最新版

Boost单闭环仿真模型在电力电子领域的应用,特别是在目标输出电压阶跃变化和负载突变这两种极端工况下的稳定闭环控制效果。首先简述了Boost单闭环仿真模型的基本构造及其工作原理,接着深入探讨了在不同条件下(如电压阶跃变化和负载突变)如何利用闭环控制系统实现快速响应和平稳过渡。文中还提出了几种提升系统稳定性的方法,包括优化控制系统设计、引入误差调节和补偿机制、合理配置参数以及增强抗干扰能力。最后强调了该模型的重要性和潜在的应用前景。 适合人群:从事电力电子相关工作的工程师和技术人员,尤其是关注电源转换效率和稳定性的专业人士。 使用场景及目标:适用于需要评估或改进现有电源管理系统稳定性的场合,旨在帮助技术人员理解和掌握Boost单闭环仿真模型的工作机理,从而更好地应对实际工程中的挑战。 其他说明:随着电力电子技术的进步,Boost单闭环仿真模型有望在未来发挥更大的作用,推动工业生产和技术革新。
recommend-type

超强编程助手源码 编程辅助工具 代码规整工具源码 web开源助手源码

KaiGe超强编程助手源码/编程辅助工具/代码规整工具源码/web开源助手源码
recommend-type

破解dex2jar: Android应用反编译与分析指南

标题中的“dex2jar”指的是一个用于将Android应用程序中的DEX文件(Dalvik可执行文件)转换成Java JAR文件的工具。这个过程被称为“DEX转JAR”,是一个逆向工程的过程,它允许开发者查看和分析Android应用程序的原始Java代码,这通常用于学习、测试和安全分析目的。破解一词在此上下文中可能用于描述不正当手段获取程序的源代码以进行修改或绕过安全机制等行为,但请注意,任何未经授权的修改和使用都可能违反法律和版权。 描述部分提供了使用dex2jar工具的基本步骤。dex2jar通常是一个批处理文件(dex2jar.bat),用于在Windows环境下执行操作。它将DEX文件(classes.dex)作为输入,并生成对应的JAR文件。这个过程需要用户已经下载并解压了dex2jar的压缩包,并将其中的dex2jar.bat文件放在一个可以访问的目录中。然后,用户需要将目标Android应用程序中的classes.dex文件复制到该目录下,并在命令行界面中运行以下命令: dex2jar.bat classes.dex 执行完毕后,会在同一目录下生成名为classes.dex.dex2jar.jar的文件。这个JAR文件实质上是将DEX文件中的类转换成了Java的.class文件,并打包成了JAR格式,供后续的分析或修改使用。 【标签】中的“Android 破解”可能被误解为破解Android应用程序的安全机制,实际上,这个标签更准确的意义是分析和理解Android应用程序的工作原理。而“jar dex”则是指JAR文件与DEX文件之间的转换关系。 【压缩包子文件的文件名称列表】中列举了几个文件名,其中“使用说明.txt”很可能是该工具的官方使用指南,提供更详细的使用说明、安装步骤和常见问题的解答。“dex2jar最新版下载dex2jar下载 2.0官方版_ - pc6下载站.url”则是一个指向PC6下载站上dex2jar工具下载页面的网页链接。“dex2jar-2.0”可能是指特定版本号的dex2jar工具压缩包。 总结以上信息,dex2jar是一个专门用于Android应用安全分析和逆向工程的工具,它将DEX文件转换成Java的JAR文件以便进行代码的查看和分析。尽管这个过程在安全研究和教育目的下是合法且有价值的,但任何使用这一工具的非法破解、侵犯版权或进行恶意行为都是不可接受的。
recommend-type

共享内存与共识算法详解

### 共享内存与共识算法详解 在分布式系统中,共享内存和共识算法是两个核心的概念。共享内存涉及到多个进程对同一数据的读写操作,而共识算法则帮助多个进程在可能存在故障的情况下达成一致的决策。下面将详细介绍这两个方面的相关知识。 #### 共享内存 共享内存的寄存器规范由Lamport在多篇论文中引入,同时定义了安全、规则和原子三种语义。 - **安全寄存器**:在三种寄存器语义中,安全寄存器提供的保证最弱。当读操作与写操作并发时,安全寄存器可能返回任意值,甚至可能是从未被写入或尝试写入的值。在多处理器机器中,进程可能并发访问实现寄存器抽象的底层硬件位置,从而导致返回任意值。在任意故障模型中
recommend-type

计算机专业本科生和研究生就业薪资待遇

<think>好的,我需要回答用户关于计算机专业本科和研究生就业薪资对比的问题。首先,我得先看看用户提供的引用资料,看看里面有没有相关的数据。 引用[4]提到,2019届计算机类本科毕业生的平均月收入是6858元,而高职是4883元。这应该可以作为本科生的参考数据。至于研究生,引用[1]指出重庆大学的计算机和软件硕士就业情况良好,薪资高于行业平均水平,但没有具体数字。不过引用[3]提到,前20名的高校多为985/211,尤其是理工类院校的毕业生薪资更高。这里可能需要结合其他信息来推断研究生的薪资水平。 另外,引用[2]提到计算机专业毕业生薪资一般在万元以上,但不确定这是否特指研究生还是包括
recommend-type

eWebEditor 10.3最新版特性与安全升级指南

从提供的信息来看,我们需要深入了解和探讨的内容主要集中在“eWebEditor最新版”这一主题上。eWebEditor是一款流行的在线HTML编辑器,它支持ASP和ASP.NET环境,并广泛用于Web内容管理。通过给出的标题和描述,以及标签和文件名称列表,我们可以推导出一系列相关的知识点。 ### 标题知识点解析 #### eWebEditor的定义与功能 “eWebEditor最新版”中提到的“eWebEditor”指的是在线HTML编辑器产品,它被广泛应用于需要在线编辑和发布网页内容的场合。编辑器通常包含许多功能,比如文本格式化、图像插入、链接管理等,提供用户友好和接近桌面程序的编辑体验。eWebEditor产品以ASP和ASP.NET作为其主要的技术平台。 #### “最新版”更新内容 “最新版”表明我们正在讨论的是eWebEditor的最新版本更新,该版本很可能是为了增加新功能、提升性能、修复已知问题或改善安全性能。一般来说,软件的更新也可能会引入对新操作系统或浏览器的兼容性,以及对现有API或开发环境的新支持。 ### 描述知识点解析 #### “亲测可用”的含义 从“亲测 可用”的描述中我们可以推断出,发布者可能已经对“eWebEditor最新版”进行了测试,并验证了其在实际使用中的性能和稳定性。该短语传递出一个积极的信号,即该版本值得信赖,用户可以期待它将正常工作,无需担心兼容性或功能缺失的问题。 ### 标签知识点解析 #### eWebEditor的版本标识 “eWebEditor ASPX 10.3 最新版”中的标签指出我们讨论的版本号为10.3,这是一个具体的产品版本,意味着它可能包含了一些特定的更新或新增特性。通过版本号,我们可以推断产品已经经过了多次迭代和改进。 #### ASPX技术框架 在标签中提到的“ASPX”,这表明eWebEditor最新版支持ASP.NET Web Forms技术,ASPX是ASP.NET网页的标准文件扩展名。这一信息指出编辑器适合使用.NET框架的网站开发环境。 ### 文件名称列表知识点解析 #### “升级说明.txt”文件 “升级说明.txt”是一个文本文件,它可能包含了eWebEditor从上一版本升级到最新版本时的变化说明,例如新增功能、改进的地方以及需要注意的变更。开发者或维护人员在升级时应该仔细阅读这些说明,以便于平滑过渡到新版本,并最大化地利用新功能。 #### “安全说明.txt”文件 “安全说明.txt”文件通常提供了关于软件安全性的相关信息,这可能包括了针对最新版的安全补丁、修复的安全漏洞列表以及安全最佳实践的建议。特别是对于在线编辑器这类直接参与网页内容生成的工具,安全尤为重要,因此,安全说明文件对于确保编辑器和整个网站的安全运行至关重要。 #### “ewebeditor”文件夹或组件 “ewebeditor”可能是实际包含eWebEditor编辑器文件的文件夹名称。通常,这类文件夹内会包含用于前端的JavaScript文件、用于后端处理的服务器端代码(ASP.NET或ASP代码),以及相关的样式文件和资源文件。对于开发者来说,了解这些文件和组件的组织结构对于集成和配置编辑器至关重要。 综合以上信息,我们可以了解到eWebEditor的最新版本更新了很多内容,可能包含性能和安全性的提升,并可能对特定的技术平台如ASP.NET提供了更好的支持。用户应该参考升级和安全说明文件,以便正确理解和应用这些更新。对于开发者而言,掌握如何在项目中部署和配置eWebEditor编辑器也是一个重要的技能点。
recommend-type

分布式系统中的时间抽象与故障处理

### 分布式系统中的时间抽象与故障处理 #### 1. 故障检测概述 在分布式系统中,存在三种不同的系统假设:异步系统假设、同步系统假设和部分同步系统假设。异步系统不包含任何时间假设,我们的进程和链路抽象直接体现了这一点。然而,这些抽象不足以定义同步和部分同步系统。 为了添加时间假设,一种方法是用时间保证来扩展进程和链路抽象,但这会导致规范过于复杂。因此,我们引入了故障检测器的抽象概念,它能提供关于哪些进程崩溃、哪些进程正常的信息,不过这些信息不一定准确。 故障检测器抽象相较于直接对进程和链路做时间假设具有以下两个优势: - 减轻了用时间假设扩展进程和链路抽象的需求,保留了这些抽象的简
recommend-type

我发一份参考课程设计目录

<think>好的,用户之前问过关于高校实验室安排系统的数据库课程设计,现在他需要一份参考的课程设计目录。首先,我需要回顾之前的对话,确保目录结构和他之前的问题相关,并且覆盖他提到的核心需求、ER模型、表结构、业务逻辑等内容。 用户现在要目录,可能是在进行课程设计的结构规划,需要明确的章节安排。我需要考虑课程设计通常包含的部分,比如需求分析、系统设计、数据库设计、实现、测试等。同时,结合之前给出的内容,比如ER图、表结构、冲突检测算法等,确保这些部分在目录中有体现。 还要注意用户可能希望目录足够详细,包含各个关键部分,比如摘要、需求分析、数据库设计(包括概念结构、逻辑结构、物理结构)、系统
recommend-type

惠普AMTBrand深度解析与技术特点

标题和描述中提到的“惠普AMTBrand”,可能是指惠普(Hewlett-Packard,简称HP)公司旗下的AMTBrand相关产品或技术。然而,由于给出的信息非常有限,我们可以先从惠普公司以及AMT(Active Management Technology,主动管理技术)两个方面进行展开。惠普是全球知名的IT企业,提供多种计算机硬件、软件、云服务和解决方案,而AMT是英特尔(Intel)研发的一种硬件级别的远程管理技术。 首先,我们来了解惠普公司: 惠普(Hewlett-Packard Enterprise,简称HPE),是全球领先的信息技术解决方案提供商。成立于1939年,由Bill Hewlett和David Packard在一间车库里创立,如今已经成为全球范围内提供广泛IT产品与服务的企业。惠普的产品和服务包括但不限于个人计算机(PC)、打印设备、工作站、服务器、网络设备、存储解决方案以及软件和服务。 惠普在IT服务管理、云计算、大数据和分析等领域均有涉猎,并为各种规模的企业提供从基础架构到应用管理的全方位解决方案。随着数字化转型的不断深入,惠普也在不断地通过研发新技术和收购相关企业来拓展其产品和服务的范围。 接着,我们探索AMT技术: AMT是英特尔推出的一种基于硬件的管理解决方案,它允许IT部门远程管理企业中的个人计算机和其他设备。AMT是一种集成在商用英特尔处理器中的技术,能够在个人电脑关机或者操作系统失效的情况下,提供网络访问以及硬件级别的远程管理功能。这项技术最初由英特尔在2006年发布,历经数代更新,为IT运维人员提供了众多功能,如远程开机、远程维护、软件部署、系统监控等。 AMT的优势主要体现在以下几个方面: 1. 远程访问:即使目标设备没有开机或操作系统出现故障,AMT也可以实现远程访问和管理。 2. 安全性:它提供比传统软件解决方案更为深入的硬件级别安全机制,确保数据传输的安全。 3. 节约成本:通过减少现场支持的需要,AMT能够帮助公司节约维护成本。 4. 提高效率:快速远程解决问题,从而提高IT部门的工作效率和响应速度。 然而,由于AMT技术基于特定的硬件和软件,这意味着用户需要购买带有AMT功能的英特尔处理器和相应的支持软件,同时可能需要来自惠普或其他OEM厂商的相应硬件。 最后,提到“压缩包子文件的文件名称列表”中的“AMTBrand”,这可能意味着提供或关联惠普AMTBrand技术的文件压缩包。考虑到文件名称的单一性和没有其他文件描述提供进一步信息,不能确定这个压缩包内具体包含哪些内容。不过,可以推测该压缩包内可能包含了介绍惠普AMTBrand技术的文档、演示、驱动程序、更新或管理工具等。 综合来看,文件中提到的“惠普AMTBrand”可能是指惠普公司与英特尔AMT技术结合后形成的产品或服务品牌,旨在为用户提供更为高效和安全的远程管理解决方案。考虑到惠普公司自身在IT领域的深厚积累和AMT技术的先进性,惠普AMTBrand很可能为企业级客户提供了重要价值。
recommend-type

分布式编程抽象:概念、应用与挑战

# 分布式编程抽象:概念、应用与挑战 ## 1. 引言 分布式编程抽象旨在解决分布式系统中多进程合作的难题,为分布式程序开发提供模块化策略。通过特定的应用程序编程接口(API),可以利用这些抽象来简化开发过程。 ## 2. 分布式计算的动机 ### 2.1 分布式系统的特点 分布式计算涉及一组寻求合作的进程。部分进程可能会因崩溃或断开连接而停止运行,这就是分布式系统的部分故障特性。正如Leslie Lamport所说:“分布式系统中,一台你甚至不知道存在的计算机故障,可能会使你自己的计算机无法使用。” ### 2.2 合作的挑战 当部分进程失败或断开连接时,仍在运行的进程需要以一致的方式