为什么我采不到电压#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_WIDTH0,WORD_HIGH1,(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(size12)temp=ascii_1206[chr][t]; //调用1206字体
else if(size16)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(enshow0&&t<(len-1))
{
if(temp0)
{
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,这代码哪有问题