×
单片机 > 单片机程序设计 > 详情

STC15W408AS单片机白光T12控制器

发布时间:2024-05-06 发布时间:
|

自己设计和制作的stc白光,附上原理图,洞洞板走线图和源代码。
只实现了简单的温控,短按一下编码器快速设定温度为300℃,双击一下编码器快速设定为10℃(相当于短暂休眠












代码注释还是很详细的,适合初学者学习。

单片机源程序如下:

/**

布满星星的天空 CZS 编写

*/

#include

#include

#include


sbit t12 = P3 ^ 7; //T12控制

sbit encoderb = P1 ^ 0; //编码器的b脚

sbit encodera = P1 ^ 1; //编码器的a脚

sbit encoderd = P1 ^ 2; //编码器的按键d脚

sbit DIO = P3 ^ 3; // TM1650 数码管驱动的sda引脚

sbit CLK = P3 ^ 2; // TM1650 数码管驱动的scl引脚

sbit DO = P5 ^ 5; //DS18B20数据脚

unsigned long VREF = 2390; // 用万用表测量基准电压的真实值,单位mv


bit lastb = 0;

bit lasta = 0;

unsigned short push_last_time = 0; //记录按下编码器按钮的时间,短按和长按


unsigned long t12_voltage; // 计算t12热电偶电压

unsigned long system_voltage; // 计算单片机供电电压

unsigned long input_voltage; // 计算整个板子的输入电压(12~24V)


// PID控制算法

#define KP 1.2f // 比例系数

#define KI 0.2f // 积分系数

#define KD 0.1f // 微分系数

#define MAX_UK 400.0f // 系统允许输出的最大控制量,这里表现为加热数,400个0.5ms加热周期,最长连续加热时间为200ms


int ek = 0, ek_1 = 0, ek_2 = 0; // 记录连续三次的偏差值(设定值-实际测量值)

float uk_1 = 0.0f, uk = 0.0f; // 记录当前计算的PID调整值和上次计算的PID调整值

long integralSum = 0; // 位置式PID算法的累计积分项


// 定义一个数码管段码表,0~F

unsigned char CODE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0X7C, 0X39, 0X5E, 0X79, 0X71};


unsigned int t12SetTemperature = 10; // 记录当前设定的温度

unsigned int t12ActualTemperature = 0; // 保存T12当前的实际温度

bit isChangeTemperature = 0; // 标记是否更改过设定温度

unsigned int setTempShowTime = 0; // 记录显示设置温度的时长


unsigned int need_heat_time = 0; // 需要加热的时长

unsigned int heat_time_count = 0; //当前已经加热的时长

unsigned int actualTempShowTime = 250; //设定当前温度的显示时长,避免采集温度过快造成数码管乱跳


/*延时函数,使用STC-ISP自动生成的,比较准确*/

void Delay_ms(unsigned int k) //@12.000MHz

{

unsigned char i, j;

for (; k > 0; k--)

{

i = 12;

j = 169;

do

{

while (--j)

;

} while (--i);

}

}


void Delay_us(unsigned int i)

{

for (; i > 0; i--)

{

_nop_();

_nop_();

_nop_();

_nop_();

}

}


// 初始化各个IO口

void initIO()

{

// 配置各个端口的输入模式,M1M0:00普通,01推挽,10高阻输入,11开漏

/*

以下列出需要配置的端口,其他端口保持默认即可

t12 = P3^7; //T12控制 推挽输出模式

ADC3:系统输入电压检测 P1^3 输入模式

ADC4:T12热电偶电压检测 P1^4 输入模式

ADC5:2.5V参考电压输入 P1^5 输入模式

*/


//P1M0 |= 0x00; //0000 0000

P1M1 |= 0x38; //0011 1000


P3M0 = 0x80; //1000 0000

P3M1 = 0x00; //0000 0000

}


/*初始化ADC*/

void initADC(void)

{

/*

开启相应ADC口的模拟输入功能(相应位置1)

ADC3:系统输入电压检测 P1^3

ADC4:T12热电偶电压检测 P1^4

ADC5:2.5V参考电压输入 P1^5

*/

P1ASF = 0x38; //0011 1000

ADC_RES = 0; // 清楚结果寄存器

ADC_RESL = 0;

/*

ADC控制寄存器

ADC_POWER | SPEED1 | SPEED0 | ADC_FLAG | ADC_START | CHS2 | CHS1 | CHS0

*/

// 这里初始化的时候,可以先打开电源和设置转换速度

ADC_CONTR = 0x80; // 1000 0000

Delay_ms(5); // 上电之后延时等待一段时间

}


// 关闭ADC电源,在进入空闲(休眠)模式的时候启用,降低功耗

void closeADC(void)

{

/*

ADC控制寄存器

ADC_POWER | SPEED1 | SPEED0 | ADC_FLAG | ADC_START | CHS2 | CHS1 | CHS0

*/

ADC_CONTR = 0x00;

}


// 直接插入排序

void insertionSort(unsigned int A[], unsigned int n)

{

unsigned int i, j;

for (i = 1; i < n; i++)

{

for (j = i; j > 0; j--)

{

if (A[j] < A[j - 1])

{

// 不使用第三变量交换两个数,使用异或运算速度快

A[j - 1] ^= A[j];

A[j] ^= A[j - 1];

A[j - 1] ^= A[j];

}

}

}

}


#define ADC_FLAG 0x10 // ADC转换完成标志

#define ADC_START 0x08 // ADC开始置位

// 获取某个ADC通道的转换值

// 为了提高结果的准确性,每次测量,测5次,并且去掉一个最高值,一个最低值,最后取中间3个的均值返回

unsigned int getADCResult(unsigned int channel)

{

unsigned int res[5], i, result = 0;

for (i = 0; i < 5; i++)

{

/*

ADC控制寄存器

ADC_POWER | SPEED1 | SPEED0 | ADC_FLAG | ADC_START | CHS2 | CHS1 | CHS0

*/

ADC_CONTR = (0x80 | channel | ADC_START); // 选择需要读取的通道,并开启转换

Delay_us(1);

while (!(ADC_CONTR & ADC_FLAG))

; //等待ADC转换完成

res[i] = ((ADC_RES << 2) | (ADC_RESL & 0x03)); // 计算转换出来的原始结果

ADC_RES = 0x00;

ADC_RESL = 0x00; // 清零结果寄存器

}

// 对结果进行排序

insertionSort(res, 5);

// 去掉一个最高值,去掉一个最低值,剩余三个求平均值

result = (res[1] + res[2] + res[3]) / 3;

return result;

}

/*以下是计算各种电压的函数,返回结果的单位都是mv*/

// 计算公式(mv) output_voltage = (VREF万用表测的TL431基准电压值(mv) * 待测通道的ADC值 / TL431基准通道ADC值)

// 计算获取T12的电压

void getT12Voltage(void)

{

t12_voltage = (VREF * getADCResult(4) / getADCResult(5)); //计算t12电压,单位mV

}


// 计算获取单片机的电源电压

void getSystemVoltage(void)

{

system_voltage = (VREF * 1024 / getADCResult(5)); //计算单片机的电源电压,单位mV;

}


// 计算获取输入电源电压

void getInputVoltage(void)

{

input_voltage = (VREF * getADCResult(3) / getADCResult(5) * 11); // 计算下分压电阻点的电压,并乘分压比,获得实际的输入电压

}


/* 计算T12热电偶温度 */

void getT12Temperature(void)

{

float x = 0.0f;

t12 = 0; //测温的时候,关闭电烙铁

Delay_us(10); // 等待一段时间,等电容放完电后再测量温度比较准确

getT12Voltage(); // 更新T12热电偶电压

//T12实际温度 = (ADC电压(mV)-失调电压(mV))/运放增益*热电偶分度值(℃/mV)+室温(℃)

//t12Temp = 1.0f*getT12Voltage() / 231.0f * 54.0f + 23.0f;


// 插值函数计算T12温度,上面的算得不够准确,自己测量了t12温度与热电偶电动势的关系,用matlab拟合出来的公式

x = 1.0f * t12_voltage / 231.0f;

x = -0.9f * x * x + 48.0f * x + 22.0f;

t12ActualTemperature = (unsigned int)x;

}


/*

// 增量式PID控制算法,该算法用在温度控制效果不佳,调参调了比较久,不是很理想

// 输入设定温度和当前温度

// 返回当前应该加热的时长

void incrementalPID(unsigned int setTemperature, unsigned int actualTemperature)

{

float delta_uk = 0.0f; // 用于计算PID增量值

uk_1 = uk; // 记录上次计算的PID调整值

ek_2 = ek_1; // 记录上上次计算的偏差值

ek_1 = ek; // 记录上次计算的偏差值

ek = setTemperature - actualTemperature; // 计算当前偏差值

if (ek < 0)

{

// 如果实际温度比设定温度还要高,那么不执行加热

need_heat_time = 0;

return;

}

if (abs(ek) > 100)

{

// 如果温差大于100℃,则执行系统的动态加速,不管比例项为正还是为负,都取正数

[1] [2] [3]
STC15W408AS单片机白光T12控制器

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
如何为单片机选择合适的负载电容