Normal mode下,sensor校准数据,恢复出厂设置,不丢失

本文详细介绍了如何在设备中实现对ACC、GYRO、PS三种传感器校准数据的备份与还原功能,包括开启产品信息支持、定义结构体、添加nvram数据、实现代码实现以及对传感器校准数据的客制化。通过这一系列步骤,可以在恢复出厂设置后自动恢复传感器校准数据,同时允许在正常模式下随时进行校准并保存最新的校准数据,以防止数据丢失。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目前支持的ACC,GYRO,PS 三种sensor的校准数据,是保存在nvram中,并且也有加入到nvram binregion中,可以实现恢复出厂设置后,sensor校准数据的恢复。
但是nvram binregion中的sensor数据是要在产线上做校准并保存的,而且永远都是这个固定值。
但是客户实际上是在normal mode下,需要随时做校准,而且需要保存最近的校准值不丢失。
因nvram binregion和sensor daemon源码不开放,所以无法将sensor nvram保存在pro_info中。
现提供对sensor nvram的backup的功能,来实现sensor数据的保存。

1. 确认打开 MTK_PRODUCT_INFO_SUPPORT
修改alps/mediatek/config/$project/ProjectConfig.mk: MTK_PRODUCT_INFO_SUPPORT=yes
MTK_PRODUCT_INFO_SUPPORT 也必须存在于 AUTO_ADD_GLOBAL_DEFINE_BY_NAME  中。
 
2. 定义所需要保存的结构体
这里定义了 ACC,GYRO,PS 三种结构体到一个backup的数据中,可以根据需要做添加或删除,文件名字可以自定义,或者添加到已有的文件中。
\mediatek\custom\$project\cgen\cfgfileinc\CFG_XXXX_File.h
//the new record for the hwmon sensor backup data
#define CFG_HWMON_BACKUP_RESERVED_SIZE (1024-CFG_FILE_HWMON_ACC_REC_SIZE-CFG_FILE_HWMON_GYRO_REC_SIZE-CFG_FILE_HWMON_PS_REC_SIZE)
typedef struct{
 NVRAM_HWMON_ACC_STRUCT hwmon_acc;
 NVRAM_HWMON_GYRO_STRUCT hwmon_gyro;
 NVRAM_HWMON_PS_STRUCT hwmon_ps;
 unsigned char reserved[CFG_HWMON_BACKUP_RESERVED_SIZE];
}HWMON_BACKUP_STRUCT;
#define CFG_FILE_HWMON_BACKUP_SIZE  sizeof(HWMON_BACKUP_STRUCT)
#define CFG_FILE_HWMON_BACKUP_TOTAL  1
 
//此结构体数据的default值
\mediatek\custom\$project\cgen\cfgdefault\CFG_XXXX_Default.h
HWMON_BACKUP_STRUCT st_hwmon_backup_default =
{
 //acc
 {0},
 //gyro
 {0},
 //ps
 {0},
 //reserved
 {0}
};


 
3. 添加新的nvram数据的定义
\mediatek\custom\$project\cgen\inc\Custom_NvRam_LID.h
//添加LID定义
    AP_CFG_RDCL_HWMON_BACKUP_LID, //new add
    AP_CFG_CUSTOM_FILE_MAX_LID,
} CUSTOM_CFG_FILE_LID;


 
//添加LID版本信息
#define AP_CFG_RDCL_HWMON_BACKUP_LID_VERNO      "000"


 
//注意此table中添加的位置,需要和 CUSTOM_CFG_FILE_LID 中的位置对应。
\mediatek\custom\$project\cgen\inc\CFG_file_info_custom.h
    const TCFG_FILE g_akCFG_File_Custom[]=
    {
       ....
        { "/data/nvram/APCFG/APRDCL/HWMON_BACKUP",   VER(AP_CFG_RDCL_HWMON_BACKUP_LID), CFG_FILE_HWMON_BACKUP_SIZE,
            CFG_FILE_HWMON_BACKUP_TOTAL, SIGNLE_DEFUALT_REC  ,    (char *)&st_hwmon_backup_default, DataReset , NULL
        },
    };


 
//Meta tool需要读取的信息
\mediatek\custom\$project\cgen\inc\Custom_NvRam_data_item.h
LID_BIT VER_LID(AP_CFG_RDCL_HWMON_BACKUP_LID)
HWMON_BACKUP_STRUCT *CFG_FILE_HWMON_BACKUP_TOTAL
{
};


 
4. 添加nvram到product_info
JB:\mediatek\custom\common\cgen\CFG_file_info.c
KK:\mediatek\external\nvram\libcustom_nvram\CFG_file_info.c
const TABLE_FOR_SPECIAL_LID g_new_nvram_lid[] = 
{
 { AP_CFG_REEB_PRODUCT_INFO_LID, 0, 1024 * 1024 },
 { AP_CFG_RDCL_HWMON_BACKUP_LID, 1024 * 1024, 1024 * 1024 },
};
 
5. 实现备份还原的code




\mediatek\external\nvram\libnvram_daemon_callback\libnvram_daemon_callback.c
int my_callback(void)
{
    ALOGD("nvram daemon callback will run!!!");
    my_nvram_daemon(); //add
    return 0;
}


 


int my_nvram_daemon(void)
{
 int err = 0, ret = 0;
 F_ID fd;
 int rec_size, rec_num;
 HWMON_BACKUP_STRUCT hwmon_backup;


 NVRAM_LOG("ready to read hwmon backup\n");
 
 /* read the hwmon backup data */
 fd = NVM_GetFileDesc(AP_CFG_RDCL_HWMON_BACKUP_LID, &rec_size, &rec_num, ISREAD);
 if(fd.iFileDesc < 0)
 {
  NVRAM_LOG("null hwmon backup file handle pointer: %d!\n", fd.iFileDesc);
  err = -EFAULT;
  return err;
 }


 ret = read(fd.iFileDesc, &hwmon_backup, (rec_size * rec_num));
 if(ret < 0)
 {
  NVRAM_LOG("read hwmon backup file error: %d!\n", ret);
  err = -EFAULT;
 }
 
 NVM_CloseFileDesc(fd);


 NVRAM_LOG("hwmon backup data, hwmon_acc:%d-%d-%d\n", hwmon_backup.hwmon_acc.offset[0], hwmon_backup.hwmon_acc.offset[1], hwmon_backup.hwmon_acc.offset[2]);


 /* set the hwmon acc data */
 fd = NVM_GetFileDesc(AP_CFG_RDCL_HWMON_ACC_LID, &rec_size, &rec_num, ISWRITE);


 ret = write(fd.iFileDesc, &hwmon_backup.hwmon_acc, (rec_size * rec_num));


 NVM_CloseFileDesc(fd);


 NVRAM_LOG("hwmon backup data, hwmon_gyro:%d-%d-%d\n", hwmon_backup.hwmon_gyro.offset[0], hwmon_backup.hwmon_gyro.offset[1], hwmon_backup.hwmon_gyro.offset[2]);


 /* set the hwmon gyro data */
 fd = NVM_GetFileDesc(AP_CFG_RDCL_HWMON_GYRO_LID, &rec_size, &rec_num, ISWRITE);


 ret = write(fd.iFileDesc, &hwmon_backup.hwmon_gyro, (rec_size * rec_num));


 NVM_CloseFileDesc(fd);


 NVRAM_LOG("hwmon backup data, hwmon_ps:%d-%d-%d\n", hwmon_backup.hwmon_ps.ps_cali[0], hwmon_backup.hwmon_ps.ps_cali[1], hwmon_backup.hwmon_ps.ps_cali[2]);


 /* set the hwmon ps data */
 fd = NVM_GetFileDesc(AP_CFG_RDCL_HWMON_PS_LID, &rec_size, &rec_num, ISWRITE);


 ret = write(fd.iFileDesc, &hwmon_backup.hwmon_ps, (rec_size * rec_num));


 NVM_CloseFileDesc(fd);


 return err;   
}


7. sensor校准客制化
这里实现了对sensor 校准数据的backup,但是在具体sensor的校准数据保存的地方,需要将数据同时保存到 AP_CFG_RDCL_HWMON_BACKUP_LID 上,否则无效。
#include "gray_nomcu.h" #include "usart.h" #include "Adc.h" No_MCU_Sensor gray;//gary是在头文件中No_MCU_Sensor结构体 后面定义的全局变量 extern No_MCU_Sensor gray; unsigned short Anolog[8] = {0}; unsigned short white[8] = {2550, 3200, 2600, 2200, 3200, 3200, 3300, 1500}; unsigned short black[8] = {500, 800, 300, 300, 100, 600, 850, 100}; unsigned short Normal[8]; /* 函数功能:采集8个通道的模拟值并进行均值滤波 参数说明:result - 存储8个通道处理结果的数组 */ void Get_Analog_value(unsigned short *result) { unsigned char i, j; unsigned int Anolag = 0; // 遍历8个传感器通道(3位地址线组合) for (i = 0; i < 8; i++) { // 通过地址线组合切换传感器通道(注意取反逻辑) Switch_Address_0(!(i & 0x01)); // 地址线0,对应bit0 Switch_Address_1(!(i & 0x02)); // 地址线1,对应bit1 Switch_Address_2(!(i & 0x04)); // 地址线2,对应bit2 // 每个通道采集8次ADC值进行均值滤波 for (j = 0; j < 8; j++) { Anolag += Get_adc_of_user(); // 累加ADC采样值 } if (!Direction) result[i] = Anolag / 8; // 计算平均值 else result[7 - i] = Anolag / 8; // 计算平均值 Anolag = 0; // 重置累加器 } } /* 函数功能:将模拟值转换为数字信号(二值化处理) 参数说明: adc_value - 原始ADC值数组 Gray_white - 白色阈值数组 Gray_black - 黑色阈值数组 Digital - 输出的数字信号(按位表示) */ void convertAnalogToDigital(unsigned short *adc_value, unsigned short *Gray_white, unsigned short *Gray_black, unsigned char *Digital) { for (int i = 0; i < 8; i++) { if (adc_value[i] > Gray_white[i]) { *Digital |= (1 << i); // 超过白阈值置1(白色) } else if (adc_value[i] < Gray_black[i]) { *Digital &= ~(1 << i); // 低于黑阈值置0(黑色) } // 中间灰度值保持原有状态 } } /* 函数功能:归一化ADC值到指定范围 参数说明: adc_value - 原始ADC值数组 Normal_factor - 归一化系数数组 Calibrated_black - 校准黑值数组 result - 存储归一化结果的数组 bits - ADC最大量程值(如255/1024等) */ void normalizeAnalogValues(unsigned short *adc_value, double *Normal_factor, unsigned short *Calibrated_black, unsigned short *result, double bits) { for (int i = 0; i < 8; i++) { unsigned short n; // 计算归一化值(减去黑电平后缩放) if (adc_value[i] < Calibrated_black[i]) n = 0; // 低于黑电平归零 else n = (adc_value[i] - Calibrated_black[i]) * Normal_factor[i]; // 限幅处理 if (n > bits) { n = bits; } result[i] = n; } } /* 函数功能:传感器结构体初始化(首次初始化) 参数说明:sensor - 传感器结构体指针 */ void No_MCU_Ganv_Sensor_Init_Frist(No_MCU_Sensor *sensor) { // 清零所有校准数据和状态 memset(sensor->Calibrated_black, 0, 16); memset(sensor->Calibrated_white, 0, 16); memset(sensor->Normal_value, 0, 16); memset(sensor->Analog_value, 0, 16); // 初始化归一化系数 for (int i = 0; i < 8; i++) { sensor->Normal_factor[i] = 0.0; } // 初始化状态变量 sensor->Digtal = 0; sensor->Time_out = 0; sensor->Tick = 0; sensor->ok = 0; // 标记未完成校准 } /* 函数功能:传感器完整初始化(带校准参数) 参数说明: sensor - 传感器结构体指针 Calibrated_white - 校准白值数组 Calibrated_black - 校准黑值数组 */ void No_MCU_Ganv_Sensor_Init(No_MCU_Sensor *sensor, unsigned short *Calibrated_white, unsigned short *Calibrated_black) { No_MCU_Ganv_Sensor_Init_Frist(sensor); // 根据配置设置ADC量程 if (Sensor_ADCbits == _8Bits) sensor->bits = 255.0; else if (Sensor_ADCbits == _10Bits) sensor->bits = 1024.0; else if (Sensor_ADCbits == _12Bits) sensor->bits = 4096.0; else if (Sensor_ADCbits == _14Bits) sensor->bits = 16384.0; // 设置采样超时时间(基础版/青春版) if (Sensor_Edition == Class) sensor->Time_out = 1; else sensor->Time_out = 10; double Normal_Diff[8]; unsigned short temp; for (int i = 0; i < 8; i++) { // 确保白值 > 黑值(必要时交换) if (Calibrated_black[i] >= Calibrated_white[i]) { temp = Calibrated_white[i]; Calibrated_white[i] = Calibrated_black[i]; Calibrated_black[i] = temp; } // 计算灰度阈值(1:2和2:1分界点) sensor->Gray_white[i] = (Calibrated_white[i] * 2 + Calibrated_black[i]) / 3; sensor->Gray_black[i] = (Calibrated_white[i] + Calibrated_black[i] * 2) / 3; // 保存校准数据 sensor->Calibrated_black[i] = Calibrated_black[i]; sensor->Calibrated_white[i] = Calibrated_white[i]; // 处理无效校准数据(全黑/全白/相等情况) if ((Calibrated_white[i] == 0 && Calibrated_black[i] == 0) || (Calibrated_white[i] == Calibrated_black[i])) { sensor->Normal_factor[i] = 0.0; // 无效通道 continue; } // 计算归一化系数 Normal_Diff[i] = (double)Calibrated_white[i] - (double)Calibrated_black[i]; sensor->Normal_factor[i] = sensor->bits / Normal_Diff[i]; } sensor->ok = 1; // 标记初始化完成 } /* 函数功能:传感器主任务(无定时器版本)*/ void No_Mcu_Ganv_Sensor_Task_Without_tick(No_MCU_Sensor *sensor) { Get_Analog_value(sensor->Analog_value); // 采集数据 convertAnalogToDigital(sensor->Analog_value, sensor->Gray_white, sensor->Gray_black, &sensor->Digtal); // 二值化处理 normalizeAnalogValues(sensor->Analog_value, sensor->Normal_factor, sensor->Calibrated_black, sensor->Normal_value, sensor->bits); // 归一化处理 } /* 函数功能:传感器主任务(带定时器版本)*/ void No_Mcu_Ganv_Sensor_Task_With_tick(No_MCU_Sensor *sensor) { if (sensor->Tick >= sensor->Time_out) // 检查是否到达采样周期 { // 执行数据采集和处理 Get_Analog_value(sensor->Analog_value); convertAnalogToDigital(sensor->Analog_value, sensor->Gray_white, sensor->Gray_black, &sensor->Digtal); normalizeAnalogValues(sensor->Analog_value, sensor->Normal_factor, sensor->Calibrated_black, sensor->Normal_value, sensor->bits); sensor->Tick = 0; // 重置定时器 } } /* 函数功能:定时器tick递增 */ void Task_tick(No_MCU_Sensor *sensor) { sensor->Tick++; } /* 函数功能:获取数字信号状态 */ unsigned char Get_Digtal_For_User(No_MCU_Sensor *sensor) { return sensor->Digtal; // 返回8位数字状态(每位对应一个传感器) } /* 函数功能:获取归一化后的数据 返回值:1-成功 0-未初始化 */ unsigned char Get_Normalize_For_User(No_MCU_Sensor *sensor, unsigned short *result) { if (!sensor->ok) return 0; else { memcpy(result, sensor->Normal_value, 16); // 拷贝归一化数据 return 1; } } /* 函数功能:获取原始校准数据 返回值:1-成功 0-未初始化 */ unsigned char Get_Anolog_Value(No_MCU_Sensor *sensor, unsigned short *result) { Get_Analog_value(sensor->Analog_value); // 重新采集数据 memcpy(result, sensor->Analog_value, 16); if (!sensor->ok) return 0; else return 1; } /************************************************功能测试函数**********************************/ // #include <include/project/project.h> static unsigned char rx_buff[256] = {0}; void Gray_Show_Anolog(No_MCU_Sensor *sensor) { // 获取传感器模拟量结果(有黑白值初始化后返回1 没有返回 0) if (Get_Anolog_Value(sensor, Anolog)) { sprintf((char *)rx_buff, "Anolog %d-%d-%d-%d-%d-%d-%d-%d\r\n", Anolog[0], Anolog[1], Anolog[2], Anolog[3], Anolog[4], Anolog[5], Anolog[6], Anolog[7]); uart0_send_string((char *)rx_buff); memset(rx_buff, 0, 256); } } void Gray_Show_Digtal(No_MCU_Sensor *sensor) { uint8_t Digtal = 0; // 获取传感器数字量结果(只有当有黑白值传入进去了之后才会有这个值!!) Digtal = Get_Digtal_For_User(sensor); sprintf((char *)rx_buff, "Digtal %d-%d-%d-%d-%d-%d-%d-%d\r\n", (Digtal >> 0) & 0x01, (Digtal >> 1) & 0x01, (Digtal >> 2) & 0x01, (Digtal >> 3) & 0x01, (Digtal >> 4) & 0x01, (Digtal >> 5) & 0x01, (Digtal >> 6) & 0x01, (Digtal >> 7) & 0x01); uart0_send_string((char *)rx_buff); memset(rx_buff, 0, 256); } void Gray_Show_Normalize(No_MCU_Sensor *sensor) { // 获取传感器归一化结果(只有当有黑白值传入进去了之后才会有这个值!!有黑白值初始化后返回1 // 没有返回 0) if (Get_Normalize_For_User(sensor, Normal)) { sprintf((char *)rx_buff, "Normalize %d-%d-%d-%d-%d-%d-%d-%d\r\n", Normal[0], Normal[1], Normal[2], Normal[3], Normal[4], Normal[5], Normal[6], Normal[7]); uart0_send_string((char *)rx_buff); memset(rx_buff, 0, 256); } } /****************************************巡线接口*************************************/ /** * @brief 灰度传感器得到数字量误差等级,以中间为0 * @param data 灰度传感器得到的数字量 * @return 误差等级,范围约为[-56, 56],中间为8 */ int GRAY_GetDigtalError(uint8_t data) { int pos = -1; for (int i = 0; i < 8; i++) { if (!(data & (1 << i))) { // 扫到黑线 pos = i; break; } } if (pos == -1) return 0; // 没有扫到黑线 return (int)((pos - 3.5) * 16); // 以中间为0,左负右正,放大误差 } /** * @brief 获取灰度传感器的模拟量误差 * * @return int 模拟量误差,具体变化量范围以黑白场校准值有关 */ int GRAY_GetAnalogError() { Get_Normalize_For_User(&gray, Normal); // 获取归一化数据 int result_1 = Normal[0] + Normal[1] + Normal[2] + Normal[3]; int result_2 = Normal[4] + Normal[5] + Normal[6] + Normal[7]; return result_1 - result_2; } /***********************************************自动校准的初始化 * ****************************************/ void Gray_Init(No_MCU_Sensor *sensor, unsigned short *Calibrated_white, unsigned short *Calibrated_black, unsigned short *current_time) { // 初始化传感器 No_MCU_Ganv_Sensor_Init(sensor, Calibrated_white, Calibrated_black); } 这是我的gray_nomcu.c #include "oled.h" #include "stdlib.h" #include "oledfont.h" #include "stdio.h" #include "delay.h" uint8_t OLED_GRAM[128][8]; void OLED_Refresh_Gram(void) { uint8_t 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_WR_Byte(uint8_t dat,uint8_t cmd) { if(cmd) OLED_DC_1; else OLED_DC_0; for(uint8_t i=0;i<8;i++) { OLED_D0_0; if(dat&0x80)OLED_D1_1; else OLED_D1_0; OLED_D0_1; dat<<=1; } OLED_DC_1; } 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) { uint8_t i,n; for(i=0;i<8;i++)for(n=0;n<128;n++)OLED_GRAM[n][i]=0X00; OLED_Refresh_Gram(); } void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t) { uint8_t 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_Fill(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t dot) { uint8_t x,y; for(x=x1;x<=x2;x++) { for(y=y1;y<=y2;y++)OLED_DrawPoint(x,y,dot); } OLED_Refresh_Gram(); } void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size,uint8_t mode) { uint8_t temp,t,t1; uint8_t y0=y; uint8_t csize=(size/8+((size%8)?1:0))*(size/2); chr=chr-' '; for(t=0;t<csize;t++) { if(size==12)temp=asc2_1206[chr][t]; else if(size==16)temp=asc2_1608[chr][t]; else if(size==24)temp=asc2_2412[chr][t]; 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; } } } } uint32_t mypow(uint8_t m,uint8_t n) { uint32_t result=1; while(n--)result*=m; return result; } void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size) { uint8_t t,temp; uint8_t enshow=0; for(t=0;t<len;t++) { temp=(num/mypow(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); } } void OLED_ShowString(uint8_t x, uint8_t y, const char *p, uint8_t size) { while (*p != '\0') // 仍然可以用 '\0' 判断结束 { 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++; } } //��ʾ���и��������� void OLED_ShowSNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size,uint8_t mode) { uint8_t t=0,temp,m=0; if(size==8)m=2; if(num<0) { OLED_ShowChar(x+(size/2+m)*t,y,'-',size,mode); num = -num; } else OLED_ShowChar(x+(size/2+m)*t,y,' ',size,mode); for(t=1;t<len+1;t++) { temp=(num/mypow(10,len-t))%10; if(temp==0) { OLED_ShowChar(x+(size/2+m)*t,y,'0',size,mode); } else { OLED_ShowChar(x+(size/2+m)*t,y,temp+'0',size,mode); } } } //��ʼ��SSD1306 void OLED_Init(void) { OLED_RES_0; delay_ms(200); OLED_RES_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_Clear(); OLED_WR_Byte(0xAF,OLED_CMD); //������ʾ } // void OLED_ShowDecimals(uint16_t x,uint16_t y,const uint8_t *p,uint8_t size,int get) // { // uint8_t test[10]; // 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++; // } // sprintf((char*)test,"%6i",get); // printf("test is %sC\n",test); // printf("\r\n"); // OLED_ShowString(x+2,y,test,size); // } void OLED_ShowDecimals(uint16_t x, uint16_t y, const char *p, uint8_t size, int get) { char test[12]; // 使用 char 类型缓冲区 // 显示前缀字符串 while (*p != '\0') // 使用空字符终止判断 { 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++; } // 格式化数值并显示 snprintf(test, sizeof(test), "%6d", get); // 使用安全的 snprintf printf("test is %sC\n", test); printf("\r\n"); OLED_ShowString(x+2, y, test, size); // 直接传递 char 数组 } //x,y:������� //num :�ֿ��еڼ������� //size:�����С //mode��ģʽ0,������ʾ;1,������ʾ void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t num, uint8_t size,uint8_t mode) { uint8_t temp,t,t1; uint8_t y0=y; //uint8_t size = 16; uint8_t csize=(size/8 + ((size%8)?1:0)) * size; //�õ�����һ���ַ���Ӧ������ռ���ֽ��� for(t=0;t<csize;t++) { // ��ֻ������16��12������ û�������������� if(size==12) temp = china_1212[num][t]; //����1212���� else if(size==16) temp = china_1616[num][t]; //����1616���� 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; } } } } 这是我的oled.c #include "delay.h" #include "gray_nomcu.h" volatile unsigned int delay_times=0; void Delay_us(uint32_t xus) { SysTick->LOAD = 72 * xus; //设置定时器重装值 SysTick->VAL = 0x00; //清空当前计数值 SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器 while(!(SysTick->CTRL & 0x00010000)); //等待计数到0 SysTick->CTRL = 0x00000004; //关闭定时器 } void delay_ms(unsigned int ms) { delay_times=ms; while(delay_times !=0); } void SysTick_Init(void) { DL_SYSTICK_config(CPUCLK_FREQ/1000); NVIC_SetPriority(SysTick_IRQn, 0); } void SysTick_Handler(void) { Task_tick(&gray); if(delay_times!=0) { delay_times--; } } volatile uint32_t timer_ticks = 0; // 定时器计数器,每次中断递增 NonBlockingDelay stop_timer; // 定义一个非阻塞延时 /** * @brief 初始化非阻塞延时结构体 * @param delay 非阻塞延时结构体指针 * @retval 无 */ void Delay_Init(NonBlockingDelay *delay) { delay->start_time = 0; delay->delay = 0; delay->active = 0; } /** * @brief 启动非阻塞延时 * @param delay 非阻塞延时结构体指针 * @param current_time 当前时间(通常为定时器计数值) * @param delay_time 延时时间 * @retval 无 */ void Delay_Start(NonBlockingDelay *delay, uint32_t current_time, uint32_t delay_time) { delay->start_time = current_time; // 记录当前时间 delay->delay = delay_time; // 设置延时时间 delay->active = 1; // 标记延时开始 } /** * @brief 检查非阻塞延时是否完成 * @param delay 非阻塞延时结构体指针 * @param current_time 当前时间(通常为定时器计数值) * @retval 1 表示延时完成,0 表示延时未完成 */ uint8_t Delay_Is_Completed(NonBlockingDelay *delay, uint32_t current_time) { if (delay->active && (current_time - delay->start_time >= delay->delay)) { delay->active = 0; // 延时完成,清除标志位 return 1; // 返回延时完成 } return 0; // 延时未完成 } 这是我的delay.c #ifndef NO_MCU_GANV_GRAYSCALE_SENSOR_CONFIG_H_ #define NO_MCU_GANV_GRAYSCALE_SENSOR_CONFIG_H_ // #include <include/bsp/bsp.h> #include <stdio.h> #include <string.h> #include "ti_msp_dl_config.h" /**************************** 传感器版本配置 ****************************/ #define Class 0 // 经典版传感器 #define Younth 1 // 青春版传感器 /**************************** ADC分辨率配置 ****************************/ #define _14Bits 0 // 14位ADC模式 #define _12Bits 1 // 12位ADC模式 #define _10Bits 2 // 10位ADC模式 #define _8Bits 3 // 8位ADC模式 /**************************** 用户可配置区域 ***************************/ // 传感器版本选择(二选一) #define Sensor_Edition Class // 使用基础版传感器 // #define Sensor_Edition Younth // 使用青春版传感器 /************************* 根据单片机自行选择 **************************/ // 输出结果方向,与预期方向不同选1 #define Direction 1 // ADC分辨率选择(四选一) // #define Sensor_ADCbits _14Bits #define Sensor_ADCbits _12Bits // #define Sensor_ADCbits _10Bits // #define Sensor_ADCbits _8Bits // 定时器功能开关(需要时取消注释) #define Use_Timer 1 /*************************** 硬件抽象层配置 ****************************/ // GPIO地址切换宏定义 #define Switch_Address_0(i) \ ((i) ? (DL_GPIO_setPins(Gray_Address_PORT, Gray_Address_PIN_0_PIN)) \ : (DL_GPIO_clearPins(Gray_Address_PORT, \ Gray_Address_PIN_0_PIN))) // 地址位0控制 #define Switch_Address_1(i) \ ((i) ? (DL_GPIO_setPins(Gray_Address_PORT, Gray_Address_PIN_1_PIN)) \ : (DL_GPIO_clearPins(Gray_Address_PORT, \ Gray_Address_PIN_1_PIN))) // 地址位1控制 #define Switch_Address_2(i) \ ((i) ? (DL_GPIO_setPins(Gray_Address_PORT, Gray_Address_PIN_2_PIN)) \ : (DL_GPIO_clearPins(Gray_Address_PORT, \ Gray_Address_PIN_2_PIN))) // 地址位2控制 // ADC值获取接口宏定义 需要自己根据单片机完成对应位数的ADC采样函数 #define Get_adc_of_user() adc_getValue() // 用户自定义ADC读取函数 /**********************************************************************/ /*************************** 传感器数据结构 ***************************/ typedef struct { unsigned short Analog_value[8]; // 原始模拟量值 int Error; // 巡线误差值 unsigned short Normal_value[8]; // 归一化后的值 unsigned short Calibrated_white[8]; // 白校准基准值 unsigned short Calibrated_black[8]; // 黑校准基准值 unsigned short Gray_white[8]; // 白平衡灰度值 unsigned short Gray_black[8]; // 黑平衡灰度值 double Normal_factor[8]; // 归一化系数 double bits; // ADC分辨率对应位数 unsigned char Digtal; // 数字输出状态 unsigned char Time_out; // 超时标志 unsigned char Tick; // 时基计数器 unsigned char ok; // 传感器就绪标志 } No_MCU_Sensor; #ifdef __cplusplus extern "C" { #endif extern No_MCU_Sensor gray; extern unsigned short Anolog[8]; extern unsigned short white[8]; extern unsigned short black[8]; extern unsigned short Normal[8]; /*************************** 函数声明区域 *****************************/ // 初始化函数 void No_MCU_Ganv_Sensor_Init_Frist(No_MCU_Sensor* sensor); // 首次初始化 void No_MCU_Ganv_Sensor_Init( No_MCU_Sensor* sensor, unsigned short* Calibrated_white, unsigned short* Calibrated_black); // 带校准参数的初始化 #ifndef Use_Timer // 任务处理函数 void No_Mcu_Ganv_Sensor_Task_Without_tick(No_MCU_Sensor* sensor); // 无时基版本 // 区别:后者使用定时器提供,需要一个1ms基准的定时器调用Task_tick(&sensor)函数,再将函数No_Mcu_Ganv_Sensor_Task_With_tick(&sensor)放入while1 // 前者只需要在while(1)里,delay 1ms,或者定时器1ms调用 // 前者优点:简单,方便,后者优点:能释放CPU,不需要通过delay完成这个任务,避免阻塞其他任务,同时避免了中断里处理事件,常驻任务优先级降低 #else void No_Mcu_Ganv_Sensor_Task_With_tick(No_MCU_Sensor* sensor); // 有时基版本 void Task_tick(No_MCU_Sensor* sensor); // 时基更新函数 #endif // 用户接口函数 unsigned char Get_Digtal_For_User(No_MCU_Sensor* sensor); // 获取数字量 unsigned char Get_Normalize_For_User(No_MCU_Sensor* sensor, unsigned short* result); // 获取归一化值 unsigned char Get_Anolog_Value(No_MCU_Sensor* sensor, unsigned short* result); // 获取模拟值 // 测试函数 void Gray_Show_Anolog(No_MCU_Sensor* sensor); void Gray_Show_Digtal(No_MCU_Sensor* sensor); void Gray_Show_Normalize(No_MCU_Sensor* sensor); // 巡线支持 int GRAY_GetAnalog(uint8_t data); int GRAY_GetAnalogError(); #ifdef __cplusplus } #endif #endif /* NO_MCU_GANV_GRAYSCALE_SENSOR_CONFIG_H_ */ 这是gray_nomcu.h 所有函数均已经定义 我要测灰度传感器返回的值显示在oled上
最新发布
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值