#include <pic.h>
#include <tenx_TM56M1522.h>
#include "TM56M1522_bsp.h"
#include "TM56M1522_OT.h"
#include "TM56M1522_sfr_config.h"
const unsigned char szTemp @0x0FFF=0; //Don't remove or remark this line.
/*********************************************************************************/
//---------------------------------------------------------------------------//
#define TM56_SCL_HIGH PA4MOD = 1; // 设置 PA4 高电平
#define TM56_SCL_LOW PA4MOD = 0; // 设置 PA4 低电平
#define TM56_SDA_HIGH PA5MOD = 1; // 设置 PA5 高电平
#define TM56_SDA_LOW PA5MOD = 0; // 设置 PA5 低电平
#define DATA_DP 0X80
#define DIS_ADDRE1 0X68 // 第一个数码管的地址
#define DIS_ADDRE2 0X6A // 第二个数码管的地址
#define DIS_ADDRE3 0X6C // 第三个数码管的地址
#define DIS_ADDRE4 0X6E // 第四个数码管的地址
#define TM_SHOWADDRE 0X48 // 显示地址
#define DATA_NULL 0X00 // 不显示
//---------------------------------------------------------------------------//
unsigned char SHUM_NUM[11]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0X40};
//unsigned char SHUM_ADDRE[4]={0x6e,0x6c,0x6a,0x68}; // 数码管段地址
const unsigned char BADJ[8]={0x11,0x21,0x31,0x41,0x51,0x61,0x71,0x01}; // 亮度调节
//---------------------------------------------------------------------------//
signed int ADC_TEMP=0; // 用于温度数据存储和在数码管数码管上显示
//---------------------------------------------------------------------------//
#define TEMPS 91
#define NTC_HIGH_PRECISION 1 //1=0.1℃ 0=1℃
unsigned int code NTCNUM[TEMPS]={ // ntc器件的数据查表
//3581,3559,3535,3511,3486,3461,3435,3408,3381,3353,
//3324,3295,3266,3234,3203,3171,3138,3105,3072,3037,
3003, //0
2968,2932,2896,2859,2823,2785,2748,2710,2672,2633,
2595,2556,2517,2478,2438,2399,2360,2321,2281,2242,
2203,2164,2125,2086,2048,2009,1971,1933,1896,1858,
1822,1785,1749,1713,1678,1643,1608,1574,1540,1507,
1475,1436,1411,1380,1349,1319,1289,1260,1231,1203,
1176,1149,1122,1096,1070,1045,1021,997,974,951,
928,906,885,864,843,823,803,784,766,747,
729,712,695,678,662,646,631,616,601,587,
573,559,546,533,520,508,496,484,473,462,
//451,440,430,420,410,400,391,382,373,365,
//356,348,340,332,325,317,310,303,296,290,
//283,277,271,265,259,253,247,242,237,231,
};
/*******************************************************************************/
//================== i2c时序函数和数码管显示函数 ============================//
//--------- i2c延时函数 -----------------------------------------------------//
void dleay_i2c(unsigned char us)
{
unsigned char i;
unsigned char k;
k=0;
for(i=0;i<us;i++)
{
k++;
}
}
//--------- TM56i2c引脚初始化函数 -------------------------------------------//
void tm56i2c_init(void)
{
// 关闭全局中断(确保原子操作)
//GIE = 0;
// 配置 PA4 和 PA5 为开漏模式(模式3)
PA4MOD = 0x3;
PA5MOD = 0x3;
// 启用全局开漏功能(如需)
// PINMODbits.HSINK = 1;
// 恢复全局中断
//GIE = 1;
// 设置引脚为输出模式
PA4MOD = 0; // PA4 设为输出
PA5MOD = 0; // PA5 设为输出
}
//--------- i2c起始信号位函数 -----------------------------------------------//
void TM1650i2c_start(void)
{
TM56_SCL_HIGH; // 确保slk和dat线都都处在释放状态
TM56_SDA_HIGH;
dleay_i2c(6);
TM56_SCL_HIGH; // 拉高时钟线
dleay_i2c(6);
TM56_SDA_LOW; // 拉低数据线
TM56_SCL_LOW; // 将时钟线也拉低
}
//--------- 判断应答位函数 --------------------------------------------------//
bit TM1650_ack(void)
{
unsigned char ack;
ack=0;
TM56_SCL_HIGH; // 将PA5引脚拉高输出高电平
PA5MOD = 1; // PA5 设为输入
TM56_SCL_LOW; // 将时钟线拉低以允许数据变化
dleay_i2c(6);
TM56_SCL_HIGH; // 将时钟线拉高以稳住现数据线状态
if(PA5MOD==0); // 如果PA5引脚为0,将ack置为1
ack=1;
TM56_SCL_LOW;
PA5MOD = 0; // PA5 设为输出
return !ack; // 返回应答位
}
//--------- 发送i2c指令数据函数 ---------------------------------------------//
void Send_i2cDat(unsigned char Dat)
{
unsigned char i;
TM56_SCL_LOW;
TM56_SDA_LOW;
dleay_i2c(6);
for(i=7;i>=0;i--)
{
if(Dat&(1<<i)) // 判断sda是否为高电平或低电平,从高到低
{
TM56_SDA_HIGH;
}
else
{
TM56_SDA_LOW;
}
}
dleay_i2c(6);
TM56_SCL_HIGH; // 拉高时钟线以稳住sda线数据
dleay_i2c(6);
TM56_SCL_LOW; // 拉低时钟线以允许sda数据变化
}
//--------- i2c停止信号位函数 -----------------------------------------------//
void TM1650i2c_stop(void)
{
TM56_SCL_HIGH; // 拉高时钟线
TM56_SDA_LOW; // 拉低数据线
dleay_i2c(6);
TM56_SDA_HIGH; // 将数据线拉高
}
//--------- 写入i2c指令地址函数 ---------------------------------------------//
void Write_i2cAddCmd(unsigned char addre,unsigned char cmd)
{
dleay_i2c(200); // 器件上电先稳定一段时间
TM1650i2c_start(); // 发送开始信号
Send_i2cDat(addre); // 写入1650器件的地址
TM1650_ack();
Send_i2cDat(cmd); // 写入1650器件相应指令
TM1650_ack();
TM1650i2c_stop(); // 发送停止信号
}
//--------- 1650器件显示初始化 ----------------------------------------------//
void TM1650_Init(void)
{
tm56i2c_init(); // 进行i2c引脚功能初始化
Write_i2cAddCmd(TM_SHOWADDRE,BADJ[6]); // 显示地址,亮度为7档
Write_i2cAddCmd(DIS_ADDRE1,DATA_NULL);
Write_i2cAddCmd(DIS_ADDRE2,DATA_NULL);
Write_i2cAddCmd(DIS_ADDRE3,DATA_NULL);
Write_i2cAddCmd(DIS_ADDRE4,DATA_NULL);
}
//--------- 显示温度函数 ----------------------------------------------------//
void Show_Temp(unsigned int adc_temp)
{
if(adc_temp<0)
{
Write_i2cAddCmd(DIS_ADDRE1,SHUM_NUM[10]); // 显示‘-’号
adc_temp=-adc_temp;
}
else
{
Write_i2cAddCmd(DIS_ADDRE1,SHUM_NUM[adc_temp/10]); // 显示第十位温度数
}
Write_i2cAddCmd(DIS_ADDRE2,SHUM_NUM[adc_temp%10]); // 始终显示个位
}
//===========================================================================//
//========================== ADC各函数 ======================================//
//-------------------- 系统时钟初始化函数 -----------------------------------//
void Sys_Init(unsigned char div ) // div:系统分频00:8分频|01:4分频|02:2分频|03:1分频
{
FASTSTP=0; //启动快时钟
asm("nop");
asm("nop");
asm("nop");
CPUCKS=1; //切换到快时钟
asm("nop");
CPUPSC = div; //系统时钟分频
asm("nop");
}
//------------------- adcio初始化函数 ---------------------------------------//
void ADCIO_Init(void)
{
PB0MOD = 6;
}
//------------------- adc初始化函数 -----------------------------------------//
void ADC_Init(void)
{
ADCIE = 0; //关闭ADC中断
ADCKS = 4; //Fsys/16分频
ADVREFS = 0; //参考电压vcc
PA3MOD = 3; //IO口模拟输入模式
}
//------------------- 获取ADC数据函数 ---------------------------------------//
unsigned int GetNum_Adc(unsigned char CH) // CH为adc通道号
{
unsigned char i;
unsigned char ADCDATL; // adc低位
unsigned int ADCDATH; // adc高位
unsigned int adc_max=0; // 最大采样值(用于滤波)
unsigned int adc_min=0XFFFF; // 采样最小值 (初始为最大值)
unsigned int adc_sun=0; // 才样次数值总和(未滤波前)
unsigned int Temp=0; // 单次采样临时存储
ADCHS=CH; // adc采样通道选择(寄存器)
for(i=0;i<10;i++) // adc采样采集十次进行滤波
{
ADST=1; // 置位adc启动位开启转换
while(ADST); // 采样完成自动置0
ADCDATH=ADCDH; // 读取高八位数据
ADCDATL=ADCTL; // 读取低四位数据
/* 数据重组(构造12位ADC值)*/
ADCDATL &= 0xF0; // 屏蔽低4位,保留高4位(0bXXXX0000)
ADCDATL >>= 4; // 右移4位得到有效低4位(0b0000XXXX)
ADCDATH<<=4; // 高8位左移4位(腾出空间给低4位)
Temp = (ADCDATH + ADCDATL); // 组合成12位数值(0x0FFF最大)
/* 更新极值和总和 */
adc_sun += Temp; // 累加到总和
if(Temp > adc_max)
{ // 检测是否为新最大值
adc_max = Temp;
}
if(Temp < adc_min)
{ // 检测是否为新最小值
adc_min = Temp;
}
}
/*-------- 数字滤波处理 --------*/
adc_sun -= adc_min; // 去除最小异常值
adc_sun -= adc_max; // 去除最大异常值
adc_sun >>= 3; // 右移3位等效于除以8(求8次采样均值)
return adc_sun; // 返回滤波后的12位有效值(0-4095)
}
//---------------- 二分查找函数 ---------------------------------------------//
unsigned int Find_NtcNum(unsigned int list,unsigned int AdcNum)
{
unsigned int *list_pt; // 指向NTCNUM数组的指针
unsigned int mid=0; // 中间索引
unsigned int left=0; // 左边界索引
unsigned int right=TEMPS-1; // 右边界索引
list_pt=&list; // 获取NTCNUM数组的首地址
/*-- 边界条件检查(处理超出表格范围的情况)--*/
if(AdcNum >= *(list_pt + 0)) // 当ADC值 >= 表格第一个值(最高温度)
return 0; // 直接返回最高温度索引
if(AdcNum <= *(list_pt + TEMPS - 1)) // 当ADC值 <= 表格最后一个值(最低温度)
return TEMPS - 1; // 直接返回最低温度索引
/*-- 二分查找核心算法 --*/
while((right - left) > 1) // 当左右索引不相邻时继续查找
{
mid = (left + right) >> 1; // 计算中间位置(等效除以2但更快)
if(AdcNum == *(list_pt + mid)) // 找到精确匹配
return mid;
else if(AdcNum > *(list_pt + mid)) // ADC值比中间值大(温度更低区域)
right = mid; // 移动右边界(因为表格是降序排列)
else if(AdcNum < *(list_pt + mid)) // ADC值比中间值小(温度更高区域)
left = mid; // 移动左边界
}
return left;
}
//---------------- 读取ADC值获取NTC温度值+线性插值 ---------------------------------------------//
signed Read_NtcNum(unsigned int list[],unsigned int ADCRT,signed char BaseValue)
{
unsigned char index = 0; // 查表得到的索引号
unsigned int deta = 0; // 相邻表项的ADC差值(用于插值)
unsigned char t = 0; // 温度插值分量(0.1℃单位)
signed int result = 0; // 最终温度计算结果
/*-- 边界条件检查 --*/
if(ADCRT >= list[0]) // ADC值 >= 表格最大值(温度最低点)
return BaseValue; // 直接返回起始温度(如-20.0℃)
if(ADCRT <= (list[TEMPS - 1])) // ADC值 <= 表格最小值(温度最高点)
{
// 计算末端温度值(BaseValue + (NUM-1)*10*0.1℃)
result = ((TEMPS - 1) * 10 + BaseValue);
return result; // 如表格100项时返回 BaseValue+990(99.0℃)
}
/*-- 核心查表操作 --*/
index = Find_NtcNum(list, ADCRT);// 调用二分查找获取相邻索引
/*-- 高精度插值模式 --*/
#if NTC_HIGH_PRECISION
// 计算相邻表项的ADC差值(需确保index+1不越界)
deta = list[index] - list[index + 1];
// 计算温度差值分量:
// (当前ADC与上边界的差值 / 总差值) * 10(转换为0.1℃单位)
// 例如:ADC差值=200,当前ADC离上边界差50 → 50/200*10=2.5个0.1℃
t = 10 * (list[index] - ADCRT) / deta;
#endif
/*-- 合成最终温度值 --*/
// BaseValue + 索引对应温度 + 插值分量
// 例如:BaseValue=-200(-20.0℃),index=20(对应2.0℃)
// 插值t=5 → 最终温度=(-200 + 200 +5)=5 → 0.5℃
result = (BaseValue + index * 10 + t);
return result; // 返回0.1℃精度的温度值
}
/*========================= MAIN ============================================*/
void main(void)
{
unsigned int temp=0;
Sys_Init(2);
TM1650_Init();
ADCIO_Init();
ADC_Init();
RDCTL |= 0x03;
while(1)
{
temp=GetNum_Adc(7);
ADC_TEMP=Read_NtcNum(NTCNUM,temp,-200);
Show_Temp(ADC_TEMP);
}
}
/*===========================================================================*/
这代码有错误吗?
最新发布