御辰135 2025-04-15 18:09 采纳率: 44.4%
浏览 8

St m 32 f 103 c 8 t 6如何进行控制感为八度灰度传感器?我这个oled显示屏上一直显示是0


#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "HD.h"
#include "MyI2C.h"

uint8_t ID;                                //定义用于存放ID号的变量
int16_t AX, AY, AZ, GX, GY, GZ;            //定义用于存放各个数据的变量

int main(void)
{
    /*模块初始化*/
    OLED_Init();        //OLED初始化
    MyI2C_Init();
    HD_Init();
    char Data;
    HD_WriteReg_NO_Data(0xDD);    
    while (1)
    {
        Data = HD_ReadReg(0xDD);

                /*显示HD*/
        OLED_ShowString(1, 1, "HD:");        //显示静态字符串
        OLED_ShowSignedNum(2, 1,Data , 8);        
        

    }
}

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

#define RCC_APB2Periph_GPIO_Type    RCC_APB2Periph_GPIOB      //RCC_APB2开启GPIO的时钟类型
#define GPIO_Type    GPIOB
#define SCL_Pin    GPIO_Pin_10
#define SDA_Pin    GPIO_Pin_11

/*引脚配置层*/

/**
  * 函    数:I2C写SCL引脚电平
  * 参    数:BitValue 协议层传入的当前需要写入SCL的电平,范围0~1
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SCL为低电平,当BitValue为1时,需要置SCL为高电平
  */
void MyI2C_W_SCL(uint8_t BitValue)             //BitAction只允许0或1,传其他值编译器会警告。
{
    GPIO_WriteBit(GPIO_Type, SCL_Pin, (BitAction)BitValue);        //根据BitValue,设置SCL引脚的电平      BitAction 是一种 枚举类型(enum),用于 表示GPIO(通用输入输出)引脚的电平状态,通常用于 设置或读取单个GPIO引脚的状态。
    Delay_us(10);                                                //延时10us,防止时序频率超过要求
}

/**
  * 函    数:I2C写SDA引脚电平
  * 参    数:BitValue 协议层传入的当前需要写入SDA的电平,范围0~1
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SDA为低电平,当BitValue为1时,需要置SDA为高电平
  */
void MyI2C_W_SDA(uint8_t BitValue)
{
    GPIO_WriteBit(GPIO_Type, SDA_Pin, (BitAction)BitValue);        //根据BitValue,设置SDA引脚的电平,BitValue要实现非0即1的特性
    Delay_us(10);                                                //延时10us,防止时序频率超过要求
}

/**
  * 函    数:I2C读SDA引脚电平
  * 参    数:无
  * 返 回 值:协议层需要得到的当前SDA的电平,范围0~1
  * 注意事项:此函数需要用户实现内容,当前SDA为低电平时,返回0,当前SDA为高电平时,返回1
  */
uint8_t MyI2C_R_SDA(void)
{
    uint8_t BitValue;
    BitValue = GPIO_ReadInputDataBit(GPIO_Type, SDA_Pin);        //读取SDA电平
    Delay_us(10);                                                //延时10us,防止时序频率超过要求
    return BitValue;                                            //返回SDA电平
}

/**
  * 函    数:I2C初始化
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,实现SCL和SDA引脚的初始化
  */
void MyI2C_Init(void)
{
    /*开启时钟*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_Type, ENABLE);    //开启GPIO_Type的时钟
    
    /*GPIO初始化*/
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Pin = SCL_Pin | SDA_Pin;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIO_Type, &GPIO_InitStructure);                    //将PB10和PB11引脚初始化为开漏输出
    
    /*设置默认电平*/
    GPIO_SetBits(GPIO_Type, SCL_Pin | SDA_Pin);            //设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
}

/*协议层*/

/**
  * 函    数:I2C起始
  * 参    数:无
  * 返 回 值:无
  */
void MyI2C_Start(void)
{
    MyI2C_W_SDA(1);                            //释放SDA,确保SDA为高电平
    MyI2C_W_SCL(1);                            //释放SCL,确保SCL为高电平
    MyI2C_W_SDA(0);                            //在SCL高电平期间,拉低SDA,产生起始信号
    MyI2C_W_SCL(0);                            //起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接
}

/**
  * 函    数:I2C终止
  * 参    数:无
  * 返 回 值:无
  */
void MyI2C_Stop(void)
{
    MyI2C_W_SDA(0);                            //拉低SDA,确保SDA为低电平
    MyI2C_W_SCL(1);                            //释放SCL,使SCL呈现高电平
    MyI2C_W_SDA(1);                            //在SCL高电平期间,释放SDA,产生终止信号
}

/**
  * 函    数:I2C发送一个字节
  * 参    数:Byte 要发送的一个字节数据,范围:0x00~0xFF
  * 返 回 值:无
  */
void MyI2C_SendByte(uint8_t Byte)
{
    uint8_t i;
    for (i = 0; i < 8; i ++)                //循环8次,主机依次发送数据的每一位
    {  //>> 是右移运算符,把数字的二进制位往右移动。
        /*两个!可以对数据进行两次逻辑取反,作用是把非0值统一转换为1,即:!!(0) = 0,!!(非0) = 1*/
        MyI2C_W_SDA(!!(Byte & (0x80 >> i)));//使用掩码的方式取出Byte的指定一位数据并写入到SDA线
        MyI2C_W_SCL(1);                        //释放SCL,从机在SCL高电平期间读取SDA
        MyI2C_W_SCL(0);                        //拉低SCL,主机开始发送下一位数据
    }
}

/**
  * 函    数:I2C接收一个字节
  * 参    数:无
  * 返 回 值:接收到的一个字节数据,范围:0x00~0xFF
  */
uint8_t MyI2C_ReceiveByte(void)
{
    uint8_t i, Byte = 0x00;                    //定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到
    MyI2C_W_SDA(1);                            //接收前,主机先确保释放SDA,避免干扰从机的数据发送
    for (i = 0; i < 8; i ++)                //循环8次,主机依次接收数据的每一位
    {
        MyI2C_W_SCL(1);                        //释放SCL,主机机在SCL高电平期间读取SDA
        if (MyI2C_R_SDA()){Byte |= (0x80 >> i);}    //读取SDA数据,并存储到Byte变量   Byte |=:比较两个数的二进制位,只要有一个是1,结果就是1
                                                    //当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0
        MyI2C_W_SCL(0);                        //拉低SCL,从机在SCL低电平期间写入SDA
    }
    return Byte;                            //返回接收到的一个字节数据
}

/**
  * 函    数:I2C发送应答位,主机接收,接收完数据后,主机就向从机发送应答
  * 参    数:Byte 要发送的应答位,范围:0~1,0表示应答,1表示非应答
  * 返 回 值:无
  */
void MyI2C_SendAck(uint8_t AckBit)
{
    MyI2C_W_SDA(AckBit);                    //主机把应答位数据放到SDA线
    MyI2C_W_SCL(1);                            //释放SCL,从机在SCL高电平期间,读取应答位
    MyI2C_W_SCL(0);                            //拉低SCL,开始下一个时序模块
}

/**
  * 函    数:I2C接收应答位
  * 参    数:无
  * 返 回 值:接收到的应答位,范围:0~1,0表示应答,1表示非应答
  */
uint8_t MyI2C_ReceiveAck(void)
{
    uint8_t AckBit;                            //定义应答位变量
    MyI2C_W_SDA(1);                            //接收前,主机先确保释放SDA,避免干扰从机的数据发送
    MyI2C_W_SCL(1);                            //释放SCL,主机机在SCL高电平期间读取SDA
    AckBit = MyI2C_R_SDA();                    //将应答位存储到变量里
    MyI2C_W_SCL(0);                            //拉低SCL,开始下一个时序模块
    return AckBit;                            //返回定义应答位变量
}


#ifndef __MYI2C_H
#define __MYI2C_H

void MyI2C_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);

#endif


#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "Delay.h"



#define HD_ADDRESS        0x98        //HD的I2C从机地址

/**
  * 函    数:HD写寄存器          写一个字节
  * 参    数:RegAddress 寄存器地址,范围:参考HD手册的寄存器描述
  * 参    数:Data 要写入寄存器的数据,范围:0x00~0xFF
  * 返 回 值:无
  */                             //写操作:0xD0(0x68 << 1 | 0)       读操作:0xD1(0x68 << 1 | 1)
void HD_WriteReg(uint8_t RegAddress, uint8_t Data)
{
    MyI2C_Start();                        //I2C起始
    MyI2C_SendByte(HD_ADDRESS);    //发送从机地址,读写位为0,表示即将写入
    MyI2C_ReceiveAck();                    //接收应答
    MyI2C_SendByte(RegAddress);            //发送寄存器地址
    MyI2C_ReceiveAck();                    //接收应答
    MyI2C_SendByte(Data);                //发送要写入寄存器的数据
    MyI2C_ReceiveAck();                    //接收应答
    MyI2C_Stop();                        //I2C终止
}

/**
  * 函    数:HD写寄存器          写一个字节
  * 参    数:RegAddress 寄存器地址,范围:参考HD手册的寄存器描述
  * 参    数:Data 要写入寄存器的数据,范围:0x00~0xFF
  * 返 回 值:无
  */                             //写操作:0xD0(0x68 << 1 | 0)       读操作:0xD1(0x68 << 1 | 1)
void HD_WriteReg_NO_Data(uint8_t RegAddress)
{
    MyI2C_Start();                        //I2C起始
    MyI2C_SendByte(HD_ADDRESS);    //发送从机地址,读写位为0,表示即将写入
    MyI2C_ReceiveAck();                    //接收应答
    MyI2C_SendByte(RegAddress);            //发送寄存器地址
    MyI2C_ReceiveAck();                    //接收应答
    MyI2C_Stop();                        //I2C终止
}


//可以自己写指定地址读多个字节




/**
  * 函    数:HD读寄存器                读一个字节
  * 参    数:RegAddress 寄存器地址,范围:参考HD手册的寄存器描述
  * 返 回 值:读取寄存器的数据,范围:0x00~0xFF
  */
uint8_t HD_ReadReg(uint8_t RegAddress)
{
    uint8_t Data;
    
    MyI2C_Start();                        //I2C起始
    MyI2C_SendByte(HD_ADDRESS);    //发送从机地址,读写位为0,表示即将写入
    MyI2C_ReceiveAck();                    //接收应答
    MyI2C_SendByte(RegAddress);            //发送寄存器地址
    MyI2C_ReceiveAck();                    //接收应答
    
    MyI2C_Start();                        //I2C重复起始
    MyI2C_SendByte(HD_ADDRESS | 0x01);    //发送从机地址,读写位为1,表示即将读取            HD_ADDRESS | 0x01 的意思是将 HD的I2C地址 的最低位强制设为1,用于指定读操作
    MyI2C_ReceiveAck();                    //接收应答
    Data = MyI2C_ReceiveByte();            //接收指定寄存器的数据
    MyI2C_SendAck(1);                    //发送应答,给从机非应答,终止从机的数据输出
    MyI2C_Stop();                        //I2C终止
    
    return Data;
}



// HD_Init 函数
void HD_Init(void)
{
    MyI2C_Init();  // 先初始化底层的 I2C
    
    // 可以根据数据手册添加更多初始化操作
    // 例如,发送软件重启命令 0xC0
//    HD_WriteReg(0xC0, 0x00);
    // 等待一段时间,确保重启完成
    // 这里可以使用 Delay 函数,假设 Delay 函数存在
//    Delay_ms(100); 
    
    // 发送 ping 命令 0xAA 检查通信
//    uint8_t response = HD_ReadReg(0xAA);
//    if (response != 0x66) {
        // 处理通信异常
//    }
}
        
#ifndef __MPU6050_H
#define __MPU6050_H

void HD_WriteReg(uint8_t RegAddress, uint8_t Data);
uint8_t HD_ReadReg(uint8_t RegAddress);
void HD_Init(void);
void HD_WriteReg_NO_Data(uint8_t RegAddress);


#endif


接线图如下:

img

img

img

请问各位朋友,我的这个程序有什么问题啊?OLED显示屏上一直都是零,检测黑白线OLED都是零,这个是感为灰度传感器,我校准过了,传感器的指示灯都没问题,检测到白线亮蓝灯,代码是不是有问题啊? St m 32 f 103 c 8 t 6

  • 写回答

4条回答 默认 最新

  • 阿里嘎多学长 2025-04-15 18:29
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    问题解答

    你使用 STM32F103C8 单片机控制 OLED 显示屏,显示屏一直显示 0,可能是因为你没有正确地初始化 OLED 显示屏或没有将灰度传感器的值转换为 OLED 显示屏可读的格式。

    首先,确保你已经正确地初始化 OLED 显示屏,包括设置显示屏的模式、设置显示屏的地址和命令等。

    其次,灰度传感器的值通常是 0-1023 之间的数字,你需要将这个值转换为 OLED 显示屏可读的格式,通常是 0-255 之间的数字。你可以使用以下公式来实现这个转换:

    gray_level = (gray_value * 255) / 1023

    其中,gray_value 是灰度传感器的值,gray_level 是转换后的值。

    最后,你需要在 OLED 显示屏上显示这个转换后的值,你可以使用 OLED 显示屏的命令来实现这个操作,例如:

    OLED_Write_Command(0x40); // 设置显示屏的地址 OLED_Write_Data(gray_level); // 写入显示屏的数据

    以下是一个简单的示例代码:

    #include "stm32f10x.h"
    #include "Delay.h"
    #include "OLED.h"
    
    int main(void) {
        // 初始化 OLED 显示屏
        OLED_Init();
    
        // 读取灰度传感器的值
        int gray_value = Read_Gray_Level();
    
        // 将灰度传感器的值转换为 OLED 显示屏可读的格式
        int gray_level = (gray_value * 255) / 1023;
    
        // 显示灰度传感器的值
        OLED_Write_Command(0x40);
        OLED_Write_Data(gray_level);
    
        return 0;
    }
    

    这个示例代码只是一个简单的示例,你需要根据你的实际情况进行修改和优化。

    评论

报告相同问题?

问题事件

  • 创建了问题 4月15日