81

主题

2

好友

1491

积分

侠之大者 当前离线

Rank: 6Rank: 6

UID
897598
帖子
1384
精华
0
经验
1491 点
金钱
1290 ¥
注册时间
2021-2-4
发表于 2024-2-24 12:10 | 显示全部楼层
本帖最后由 mchoi518 于 2024-2-25 10:25 编辑

去年年底开始学习软控,先是做了一个简单的STM8S103主控,只能出声的ES9038Q2M解码,新手入门可以参考下面帖子,有软控开发基础知识。

http://bbs.hifidiy.net/forum.php ... &tid=1501716&extra=


为了更上一步,为自己制定了如下目标,并制作了一个配套的解码+耳放 “学习机”。

  1) 解码芯片软控(软件I2C):单声道输出设置、SPDIF输入设置(CSR8675蓝牙模块是SPDIF输出)、音量控制
  2) 输入和输出选择:输入USB/BT选择,输出PHONE/RCA选择
  3) 继电器音调 or DAC内置音量选择
  4) 音量调节和静音:音量可以通过继电器音调,也可以通过DAC音量寄存器。静音状态下调整音量和音量控制方式时可以回复音量
  5) EC11编码器功能:旋转调音量,短按输入选择,长按(1秒以上)输出选择
  6) OLED屏显(软件SPI):开机画面显示,正常播放画面显示。显示输入、输出、音量控制、音量及单位、PCMDSD、采样率显示。电路原因位深没能读取。
  7) 红外遥控:以上2345所有功能,外加通过重新执行main函数得到软重启效果 (本解码耳放电路没有设计遥控开关,只有背面电源开关)
  8) 通过STM8S芯片内置EEPROM保存所有状态,开机载入关机前状态。

软件部分特别感谢”丰年好大雪”大师,从他那里学到很多~

1. 学习机硬件部分

先上硬件系统整体示意图
11.JPG

全部是手里闲置原件做的,除了机壳和PCB新购~

▶主电源板子没有原理图,用sprint layout画的,简单的整流稳压电路。 输出1个12v,2个5v,一组+-15v。
1.JPG

微信图片_20240224103256.jpg

微信图片_20240224123946.jpg


▶解码耳放板子原理图、PCB、实物图
为什么可以叫耳放,因为IV LPF电路增益大概4~5倍,可以输出8~10VRMS,输出缓冲运放使用SS2590,静态电流30ma~

2.JPG

主控芯片用了STM8S105,有32K闪存,字体库够用
*电路原理图已修改,与下面代码一致
3.JPG

4.JPG

5.JPG

继电器音量用了7个继电器,0~127DB,1DB步进。可以去下面链接计算阻值
https://www.vaneijndhoven.net/jo ... lculator/index.html
继电器音量电路:用PD0~PD6的7个脚控制,用ULN2003电流放大非门芯片,
可以把音量VOLUME值的2位码直接输出,用一个GPIO_Write(GPIOD, VOLUME);语句搞定。
通过ULN2003得到反码,7个继电器的另一头是12v,低电平吸合~

6.JPG

7.JPG

8.JPG

微信图片_20240224103318.jpg

微信图片_20240224103321.jpg

微信图片_20240224103338.jpg

微信图片_20240224103342.jpg

开始把红外画到PF端口,但PF没有中断,只能飞线改成PE端口
微信图片_20240224103347.jpg

I2C改SPI,在芯片上加了3根线。I2C容易花屏,SPI好多了
*电路原理图已修改,与下面代码一致
微信图片_20240224103353.jpg

微信图片_20240224103357.jpg

▶制作,这个壳子商家面板开孔费太贵,买了个电磨机自己开的孔,电磨机比解码器还贵~
微信图片_20240224103312.jpg

微信图片_20240224103315.jpg

▶整机效果,屏幕效果
微信图片_20240224103414.jpg

微信图片_20240224103411.jpg

微信图片_20240224103406.jpg

微信图片_20240224103430.jpg

微信图片_20240224103433.jpg

微信图片_20240224103435.jpg

微信图片_20240224123951.jpg

贴片焊的比较整齐吧,哈哈~
微信图片_20240224133214.jpg

微信图片_20240224142407.jpg

虽然只是学习机,不能做的太寒酸,否则没有学习热情~哈哈

2. 软件部分

下面代码也是STM8S标准库写的。
如果新手,开发环境搭建、基本的调试等等,可以去之前的帖子学习: http://bbs.hifidiy.net/forum.php ... &tid=1501716&extra=


▶主程序main.c

所有行都加了备注,尽量模块化,重复和无用代码删除,变量等代码可读性都较好。
而且经过了一周的反复调试,自认为没有大的BUG了。
适合新手学习用~哈哈

代码功能的理解,仔细看下面代码注释就可以了~ 可以直接复制了使用。

/*******************************************************************************
代码仅供学习使用,不允许商业用途

STM8S标准库使用:
  1) stm8s_clk                        时钟
  2) stm8s_exti                        外部中断,用于编码器和红外遥控
  3) stm8s_flash                        EEPROM存储,用于存储输入/输出/音量/音控方式
  4) stm8s_gpio                        GPIO控制
  5) stm8s_tim1                        计时器1,用于定时读取解码芯片状态
  6) stm8s_tim2                        计时器2,用于红外遥控
  7) stm8s_tim3                        计时器3,用于EC11长按

扩展库使用:
  1) i2c.c                                软件i2c库文件
  2) oled.c                                1.3寸12864 OLED购买商家那里得到的
  3) remote.c                        红外遥控库文件

development by mchoi 20240221
*******************************************************************************/


/**********库文件引用**********/
#include "stm8s.h"                                                                // 里面STM8S105定义要打开
#include "oled.h"                                                                // OLED附带的SPI程序头文件
#include "bmp.h"                                                                // OLED附带的图片程序头文件
#include "i2c.h"                                                                        // 软件I2C程序头文件
#include "remote.h"                                                                // 红外遥控程序头文件

/**********定义固定值**********/
#define EC11_A_PIN      GPIO_PIN_5                                        // 定义EC11编码器引脚A
#define EC11_B_PIN      GPIO_PIN_6                                        // 定义EC11编码器引脚B
#define EC11_E_PIN      GPIO_PIN_7                                        // 定义EC11编码器引脚E
#define DAC_ADDR_L      0x90                                                // 左声道ES9038Q2M I2C地址,ADDR引脚接地
#define DAC_ADDR_R      0x92                                                // 右声道ES9038Q2M I2C地址,ADDR引脚拉高

/**********定义全局变量**********/
u8 INPUT;                                                                                // 输入选择值:       0 USB;1 BT
u8 INPUT_OLD;                                                                        // 输入选择过去值
u8 OUTPUT;                                                                        // 输出选择值:       0 PHONE;1 RCA
u8 OUTPUT_OLD;                                                                // 输出选择过去值
u8 VOLUME;                                                                        // 音量:             0~127
u8 VOLUME_OLD;                                                                // 音量过去值
u8 VOL255;                                                                        // DAC寄存器音量格式:0~255
u8 VOLCTRL;                                                                        // 音量控制方式:     0 继电器音调;1 DAC内置音调
u8 VOLCTRL_OLD;                                                                // 音量控制方式过去值
u8 MUTE = 0;                                                                        // 静音状态值:       0 非静音;1 静音
u8 MUTE_OLD = 0;                                                                // 静音状态过去值
u8 RESTART = 0;                                                                // main重新执行:     0 非重启;1 重启
u8 IR_DATA[4];                                                                        // 数组,遥控器地址码、地址反码、键值码、键值反码

/**********解码器初始化函数**********/
void DAC_Init(void)
{
    GPIO_Init(GPIOA, (GPIO_Pin_TypeDef)(GPIO_PIN_1 | GPIO_PIN_2), GPIO_MODE_OUT_PP_HIGH_FAST);    // GPIOA初始化,PD1和PD2脚
    GPIO_Init(GPIOD, (GPIO_Pin_TypeDef)(GPIO_PIN_ALL), GPIO_MODE_OUT_PP_LOW_FAST);            // GPIOD所有引脚初始化低电平,开机静音
  
    GPIO_WriteLow(GPIOA, (GPIO_Pin_TypeDef)GPIO_PIN_1);                         // 连接两个DAC芯片RESETB脚的PA1输出低电平
    delay_ms(2);                                                                                                // 延迟2ms
    GPIO_WriteHigh(GPIOA, (GPIO_Pin_TypeDef)GPIO_PIN_1);                        // 连接两个DAC芯片RESETB脚的PA1输出高电平
    delay_ms(2);                                                                                                // 延迟2ms
}

/**********编码器初始化函数**********/
void EC11_Init(void)
{
    GPIO_DeInit(GPIOC);
    GPIO_Init(GPIOC, (GPIO_Pin_TypeDef)(EC11_A_PIN | EC11_E_PIN), GPIO_MODE_IN_FL_IT);          // 配置EC11_A和E引脚为输入,有中断
    GPIO_Init(GPIOC, (GPIO_Pin_TypeDef)EC11_B_PIN, GPIO_MODE_IN_PU_NO_IT);                      // 配置EC11_B引脚为输入,无中断

    TIM3_DeInit();                                                              // TIM3初始化,用于编码器按键时间计时
    TIM3_TimeBaseInit(TIM3_PRESCALER_16384, 65535);                             // 16M分频后大概1ms一次计数,65535计数最大值也是溢出值
    TIM3_ARRPreloadConfig(ENABLE);                                              // 直到更新事件后,ARR预装载寄存器的值才传给影子寄存器
   
    EXTI_DeInit();                                                              // 外部中断初始化
    EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOC, EXTI_SENSITIVITY_FALL_ONLY);     // 配置外部中断,下降沿触发

    rim();                                                                      // 开启全局中断
}

/**********TIM1定时器初始化函数**********/
void TIM1_Init(void)
{
    TIM1_DeInit();                                                              // TIM1定时器初始化
    TIM1_TimeBaseInit(16000,TIM1_COUNTERMODE_UP,1000,3);                        // 分频16000,上升延计数,计数1000次,3次就是3秒
    TIM1_ARRPreloadConfig(ENABLE);                                              // 使能自动重装
    TIM1_ITConfig(TIM1_IT_UPDATE,ENABLE);                                       // TIM1中断使能
    TIM1_Cmd(ENABLE);                                                           // TIM1命令使能
  
    rim();                                                                      // 开启全局中断
}

/**********内部EEPROM写函数**********/
void EEPROM_WriteByte(uint16_t address, uint8_t data)
{
    FLASH_Unlock(FLASH_MEMTYPE_DATA);                                           // 解锁
    FLASH_EraseByte(address);                                                   // 擦除
    FLASH_ProgramByte(address, data);                                           // 写入数据
    FLASH_Lock(FLASH_MEMTYPE_DATA);                                             // 锁定
}

/**********编码器按键时间计时函数**********/
u16 EC11_Time(void)
{
    u16 y;                                                                      // 定义一个临时变量
   
    TIM3_SetCounter(0);                                                         // 清空定时器的值
    TIM3_Cmd(ENABLE);                                                           // 开启定时器
    while(!GPIO_ReadInputPin(GPIOC, EC11_E_PIN)){}                              // 等待低电平结束
    y=TIM3_GetCounter();                                                        // 计数结果传给y
    TIM3_Cmd(DISABLE);                                                          // 关闭定时器
   
    return y;                                                                   // 返回y值
}

/**********INPUT处理函数**********/
void INPUT_OP(void)
{
    if (INPUT == 0)
    {
      IIC_Write(DAC_ADDR_L,1,0xC4);                                             // 1号寄存器INPUT SELECT : DSD or SERIAL
      IIC_Write(DAC_ADDR_R,1,0xC4);                                             // 1号寄存器INPUT SELECT : DSD or SERIAL
      OLED_ShowString(0,0,"USB",16);                                            // 显示输入状态
    }
    else
    {
      IIC_Write(DAC_ADDR_L,1,0xC1);                                             // 1号寄存器INPUT SELECT : SPDIF
      IIC_Write(DAC_ADDR_R,1,0xC1);                                             // 1号寄存器INPUT SELECT : SPDIF
      OLED_ShowString(0,0,"BT ",16);                                            // 显示输入状态
    }
}

/**********OUTPUT处理函数**********/
void OUTPUT_OP(void)
{
    if (OUTPUT == 0)
    {
      GPIO_WriteLow(GPIOA, (GPIO_Pin_TypeDef)GPIO_PIN_2);                       // 控制输出继电器
      OLED_ShowString(0,3,"PHONE",16);                                          // 显示输出状态
    }
    else
    {
      GPIO_WriteHigh(GPIOA, (GPIO_Pin_TypeDef)GPIO_PIN_2);                      // 控制输出继电器
      OLED_ShowString(0,3,"RCA  ",16);                                          // 显示输出状态
    }
}

/**********VOLUME处理函数**********/
void VOLUME_OP(void)
{
    if (VOLCTRL == 0)
      GPIO_Write(GPIOD, VOLUME);                                                // 继电器音量更新
    else
    {
      if(VOLUME == 0) VOL255 = 255;                                             // 将显示音量0~127换算成0~255
      else VOL255 = 254 - VOLUME * 2;
      IIC_Write(DAC_ADDR_L,15,VOL255);                                          // 15号音量寄存器更新
      IIC_Write(DAC_ADDR_L,16,VOL255);                                          // 16号音量寄存器更新
      IIC_Write(DAC_ADDR_R,15,VOL255);                                          // 15号音量寄存器更新
      IIC_Write(DAC_ADDR_R,16,VOL255);                                          // 16号音量寄存器更新
    }
   
    OLED_ShowString(110,6,"dB",16);                                             // 显示音量单位
    OLED_ShowNum(62,4,VOLUME,3,32);                                             // 显示音量
}

/**********VOLCTRL处理函数**********/
void VOLCTRL_OP(void)
{
    if (VOLCTRL == 0)
    {
      IIC_Write(DAC_ADDR_L,15,0);                                               // 音量寄存器设0最大音量
      IIC_Write(DAC_ADDR_L,16,0);                                               // 音量寄存器设0最大音量
      IIC_Write(DAC_ADDR_R,15,0);                                               // 音量寄存器设0最大音量
      IIC_Write(DAC_ADDR_R,16,0);                                               // 音量寄存器设0最大音量
      OLED_ShowString(0,6,"RVOL",16);                                           // 显示音量控制方式-继电器音调
    }
    else
    {
      GPIO_Write(GPIOD, 0xFF);                                                  // 继电器音量设置最大音量
      OLED_ShowString(0,6,"DVOL",16);                                           // 显示音量控制方式-DAC内置音调
    }
}

/**********TIM1定时中断处理入口**********/
INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11)
{
    sim();                                                                      // 停止全局中断
  
    u8 PCMDSD;                                                                  // 定义一个临时变量保存I2C读取结果
    u8 DPLL;                                                                    // 存储DAC的66~68号寄存器的值
    u16 SR=0;                                                                   // 保存采样率值
   
    /**********读取DAC状态**********/
    PCMDSD = IIC_Read(DAC_ADDR_L,96);                                           // I2C读取一个DAC的96号寄存器:DSD 1/49,PCM 2,SPDIF 4/52
   
    DPLL = IIC_Read(DAC_ADDR_L,66);                                             // 读取66~69号寄存器DPLL值
    DPLL = IIC_Read(DAC_ADDR_L,67);
    DPLL = IIC_Read(DAC_ADDR_L,69);
    DPLL = IIC_Read(DAC_ADDR_L,68);                                             // 只判断68号寄存器
   
    if(DPLL == 0)                                                               // 如果DPLL位0,无信号
    {
      OLED_ShowString(48,0,"   ",16);                                           // PCMDSD显示位置擦除
      OLED_ShowString(76,0,"   ",16);                                           // 采样率数值位置擦除
      OLED_ShowString(104,0,"   ",16);                                          // 采样率单位擦除
    }
   
    /**********显示DAC状态**********/
    else
    {
      if(PCMDSD == 1)                                                           // 如果值是1,DSD
      {
        if(DPLL == 57)       SR = 64;                                           // 100Mhz时钟,68号寄存器数值对应的DSD格式
        if(DPLL == 115)      SR = 128;
        if(DPLL == 230)      SR = 256;
        if(DPLL == 205)      SR = 512;
         
        OLED_ShowString(48,0,"DSD",16);                                         // 显示DSD
        OLED_ShowNum(76,0,SR,3,16);                                             // 屏幕显示DSD格式值
        OLED_ShowString(104,0,"   ",16);                                        // 采样率单位擦除
      }
      else if(PCMDSD == 2)                                                      // 如果值是2,PCM
      {
        if(DPLL == 28)       SR = 44;                                           // 100Mhz时钟,68号寄存器数值对应的采样率
        if(DPLL == 31)       SR = 48;
        if(DPLL == 57)       SR = 88;
        if(DPLL == 62)       SR = 96;
        if(DPLL == 115)      SR = 176;
        if(DPLL == 125)      SR = 192;
        if(DPLL == 231)      SR = 352;
        if(DPLL == 251)      SR = 384;
         
        OLED_ShowString(48,0,"PCM",16);                                         // 否则显示PCM
        OLED_ShowNum(76,0,SR,3,16);                                             // 屏幕显示采样率值
        OLED_ShowString(104,0,"Khz",16);                                        // 屏幕显示采样率单位
        }
    }

    TIM1_ClearITPendingBit(TIM1_IT_UPDATE);                                     // TIM1的标志位清零
   
    rim();                                                                      // 开启全局中断
}

/**********编码器中断处理入口**********/
INTERRUPT_HANDLER(EXTI_PORTC_IRQHandler, 5)
{
    sim();                                                                      // 停止全局中断
    delay_ms(1);                                                                // 基本的去抖动延时
    u16 time;                                                                   // 定义一个临时变量保存编码器按键时间

    /**********编码器按键处理**********/
    if (GPIO_ReadInputPin(GPIOC, EC11_E_PIN) == 0)                              // 判断是否E脚触发中断
    {
      time = EC11_Time();                                                       // 读取按键时间
      
      if(time<1000)                                                             // 判断按键时间是否小于1秒
      {
        if (INPUT==0) INPUT=1;                                                  // 更换输入状态,0是USB,1是蓝牙
        else INPUT=0;
      }
      else                                                                      // 1秒以上视为长按
      {
        if (OUTPUT==0) OUTPUT=1;                                                // 更换输出状态,0是PHONE,1是RCA
        else OUTPUT=0;
      }
    }

    /**********编码器旋转处理**********/
    else
    {
      if (GPIO_ReadInputPin(GPIOC, EC11_B_PIN) == 0)                            // 判断是否B脚触发中断:B脚低电平顺时针,否则逆时针
      {
        if (VOLUME<127) VOLUME++;                                               // 音量加,最高127
        else VOLUME=127;
      }
   
      else                                                                      // 音量减,最低0
      {
        if (VOLUME>0) VOLUME--;
        else VOLUME=0;
      }
    }
   
    rim();                                                                      // 开启全局中断
}

/**********红外遥控中断处理入口**********/
INTERRUPT_HANDLER(EXTI_PORTE_IRQHandler, 7)
{
    u16 time;                                                                   // 定义临时变量保存高、低电平维持时间
    u8 i,j,data=0;                                                              // 定义临时变量,用于循环解码
   
    /**********引导码处理**********/
    time=IR_GetTime_L();                                                        // 得到低电平时间,函数定义在remote.c
    if(time<5500||time>10000)return;                                            // 标准时间: 9000us,否则退出中断服务
    time=IR_GetTime_H();                                                        // 得到高电平时间,函数定义在remote.c
    if(time<1300||time>5500)return;                                             // 标准时间4500us,否则退出中断服务

    /**********重复码处理**********/
    if(time>1300&&time<3000)                                                    // 先处理重复码,重复码标准时间 2250us
    {
      if(IR_DATA[2]==128 || IR_DATA[2]==193)                                    // 遥控器上→按键或音量+按键,长按产生重复码
      {
          if (VOLUME<127) VOLUME++;
          else VOLUME=127;
      }
      if(IR_DATA[2]==129 || IR_DATA[2]==153)                                    // 遥控器上←按键或音量-按键,长按产生重复码
      {
          if (VOLUME>0) VOLUME--;
          else VOLUME=0;
      }
    delay_ms(1);                                                                // 延迟1ms跳过560us信号,长按时下个重复码再次促发中断
    return;
    }
      
    /**********正常码解码**********/
    for(i=0;i<4;i++)                                                            // 4组按顺序是:遥控器地址码、地址反码、键值码、键值反码
    {
        for(j=0;j<8;j++)                                                        // 8位数字循环读取
        {
             time=IR_GetTime_L();                                               // 得到低电平时间
             if(time<400||time>700)return;                                      // 标准时间: 560us,否则退出中断服务
            
             time=IR_GetTime_H();                                               // 得到高电平时间
             if(time>1400&&time<1800)                                           // 数据"1" 1680us
             {
                data>>=1;                                                       // 右移一位
                data|=0x80;                                                     // 位或10000000
             }
             else if(time>400&&time<700)                                        // 数据"0" 560us
             {
                data>>=1;                                                       // 右移一位
             }
             else return;                                                       // 否则退出中断服务
        }
        IR_DATA=data;                                                       // 存放解码成功的值
    }
  
    /**********键值处理**********/                                              // 只判断数组第3组8位键值,地址码和反码校验省略
    if(IR_DATA[2]==128 || IR_DATA[2]==193)                                      // 音量加
    {
        if (VOLUME<127) VOLUME++;
        else VOLUME=127;
    }
    if(IR_DATA[2]==129 || IR_DATA[2]==153)                                      // 音量减
    {
        if (VOLUME>0) VOLUME--;
        else VOLUME=0;
    }
    if(IR_DATA[2]==197)                                                         // 输入选择
    {
        if (INPUT==0) INPUT=1;
        else INPUT=0;
    }
    if(IR_DATA[2]==136)                                                         // 输出选择
    {
        if(OUTPUT==0) OUTPUT=1;
        else OUTPUT=0;
    }
    if(IR_DATA[2]==206)                                                         // 音量控制方式选择
    {
        if(VOLCTRL==0) VOLCTRL=1;
        else VOLCTRL=0;
    }
    if(IR_DATA[2]==130)                                                         // 静音
    {
        if(MUTE==0) MUTE=1;
        else MUTE=0;
    }
    if(IR_DATA[2]==220)                                                         // 复位重启
    RESTART = 1;

    delay_ms(100);                                                              // 延迟100ms,跳过一个周期108ms后退出中断服务
    return;
}


/**********主程序**********/
void main(void)
{
    START:
  
    /**********各种初始化**********/
    Clk_Init();                                                                 // 时钟初始化,定义在remote.c
    IIC_Init();                                                                 // I2C初始化,定义在i2c.c
    DAC_Init();                                                                 // 解码器初始化
    EC11_Init();                                                                // 编码器初始化
    Remote_Init();                                                              // 遥控初始化,定义在remote.c
    OLED_Init();                                                                // OLED初始化,定义在oled.c

    /**********开机画面**********/
    OLED_ShowString(6,3,"Design",16);                                           // 开机画面,显示本人签名
    OLED_ShowString(62,3,"by",16);
    OLED_ShowString(86,3,"Mchoi",16);

    /**********读取关机前状态**********/
    INPUT = FLASH_ReadByte(0x4000);                                             // 读取EEPROM上次保存的输入选择状态
    OUTPUT = FLASH_ReadByte(0x4001);                                            // 读取EEPROM上次保存的输出选择状态
    VOLUME = FLASH_ReadByte(0x4002);                                            // 读取EEPROM上次保存的音量值
    VOLCTRL = FLASH_ReadByte(0x4003);                                           // 读取EEPROM上次保存的音量控制方式

    /**********DAC寄存器设置**********/
    IIC_Write(DAC_ADDR_L,2,0x30);                                               // MAPPING CH1,将CH1和CH2都设置为CH1
    IIC_Write(DAC_ADDR_L,8,0x99);                                               // GPIO CONFIG : INPUT SELECT
    IIC_Write(DAC_ADDR_L,11,0x30);                                              // SPDIF SELECT : GPIO1
    IIC_Write(DAC_ADDR_L,14,0x42);                                              // SOFT START
    IIC_Write(DAC_ADDR_L,21,0x50);                                              // GPIO INPUT SELECT : SPDIF
        
    IIC_Write(DAC_ADDR_R,2,0x35);                                               // MAPPING CH2,将CH1和CH2都设置为CH2
    IIC_Write(DAC_ADDR_R,8,0x99);                                               // GPIO CONFIG : INPUT SELECT
    IIC_Write(DAC_ADDR_R,11,0x30);                                              // SPDIF SELECT : GPIO1
    IIC_Write(DAC_ADDR_R,14,0x42);                                              // SOFT START
    IIC_Write(DAC_ADDR_R,21,0x50);                                              // GPIO INPUT SELECT : SPDIF
        
    /**********开机状态处理**********/
    delay_ms(3000);                                                             // 延迟3秒,开机画面维持3秒
    OLED_Clear();                                                               // OLED清屏

    INPUT_OP();                                                                 // 运行输入处理函数
    OUTPUT_OP();                                                                // 运行输出处理函数
    VOLUME_OP();                                                                // 运行音量处理函数
    VOLCTRL_OP();                                                               // 运行音量控制方式处理函数

    TIM1_Init();                                                                // TIM1定时器初始化

    /**********主循环**********/                                                // 通过主循环,各值变化时运行相应操作
    while (1)
        {        

          /**********INPUT变化时执行**********/
          if (INPUT != INPUT_OLD)                                               // 判断INPUT是否变化
          {
            INPUT_OLD = INPUT;                                                  // 先更新INPUT_OLD
            EEPROM_WriteByte(0x4000, INPUT);                                    // 记录新的值到EEPROM
            INPUT_OP();                                                         // 运行处理函数
          }

          /**********OUTPUT变化时执行**********/
          if (OUTPUT != OUTPUT_OLD)                                             // 判断OUTPUT是否有变化
          {
            OUTPUT_OLD = OUTPUT;                                                // 先更新OUTPUT_OLD
            EEPROM_WriteByte(0x4001, OUTPUT);                                   // 记录新的值到EEPROM
            OUTPUT_OP();                                                        // 运行处理函数
          }

          /**********VOLUME变化时执行**********/
          if (VOLUME != VOLUME_OLD)                                             // 判断VOLUME是否有变化
          {
            VOLUME_OLD = VOLUME;                                                // 先更新VOLUME_OLD
            EEPROM_WriteByte(0x4002, VOLUME);                                   // 记录新的值到EEPROM
            if (MUTE==1) MUTE=0;                                                // 如果静音状态,改变MUTE以执行下面MUTE部分
            else VOLUME_OP();                                                   // 否则运行处理函数
          }
         
          /**********VOLCTRL变化时执行**********/
          if (VOLCTRL != VOLCTRL_OLD)                                           // 判断VOLCTRL是否有变化
          {
            VOLCTRL_OLD = VOLCTRL;                                              // 先更新VOLCTRL_OLD
            EEPROM_WriteByte(0x4003, VOLCTRL);                                  // 记录新的值到EEPROM
            if (MUTE==1) MUTE=0;                                                // 如果静音状态,改变MUTE以执行下面MUTE部分
            else                                                                // 否则运行处理函数
            {
              VOLUME_OP();
              VOLCTRL_OP();
            }
          }
         
          /**********MUTE变化时执行**********/
          if (MUTE != MUTE_OLD)                                                 // 判断MUTE是否有变化
          {
            MUTE_OLD = MUTE;                                                    // 先更新MUTE_OLD
            if (MUTE == 0)                                                      // 如果非静音
            {
              OLED_ShowString(62,4,"    ",32);                                  // 擦除"MUTE"
              VOLUME_OP();                                                      // 恢复音量
              VOLCTRL_OP();                                                     // 恢复音量控制方式
            }
            else                                                                // 如果静音
            {
              GPIO_Write(GPIOD, 0);                                             // 继电器音量设置最小
              IIC_Write(DAC_ADDR_L,15,255);                                     // 音量寄存器设置最小
              IIC_Write(DAC_ADDR_L,16,255);                                     // 音量寄存器设置最小
              IIC_Write(DAC_ADDR_R,15,255);                                     // 音量寄存器设置最小
              IIC_Write(DAC_ADDR_R,16,255);                                     // 音量寄存器设置最小
              OLED_ShowString(62,4,"MUTE",32);                                  // 显示"MUTE"
            }
          }

          /**********RESTART变化时执行**********/                               // 重新执行main函数达到软件重置效果
          if (RESTART == 1)                                                     // 如果RESTART变为1
          {
            RESTART = 0;                                                        // 先更新RESTART值
            TIM1_Init();                                                        // 因TIM1在开机3秒后才初始化,所以这里先处理
            goto START;                                                         // 回到main函数START位置,重新执行main
          }

          delay_ms(1);                                                          // 延迟1ms循环
        }
}



#ifdef USE_FULL_ASSERT                                                          // 调试用,使能断言

void assert_failed(u8* file, u32 line)
{
  while (1)
  {
  }
}
#endif


**上面代码整体概括说明:
  先定义必要的库函数,针脚,全局变量等;
  再定义函数,各种初始化,各种操作可以模块化的;
  写中断入口函数,包括定时中断、编码器中断、红外遥控中断;
  主程序里面先执行开机各种初始化和屏幕显示、寄存器读取和写入,然后主循环读取各种值的变化。

** 自己的红外遥控器的键值如何知晓?可以先写好代码,在线调试时,读取IR_DATA[2]数值,然后写到程序里

捕获.JPG


▶main.c和配套的库文件下载

上面代码main.c文件
main.zip (5.84 KB, 下载次数: 78)

评分

参与人数 5经验 +28 魅力 +10 收起 理由
HuLidiy + 3 + 3 赞一个!
gztankboy + 2 很给力!
彭星 + 3 + 3 赞一个!
new1510 + 20 技术贴
naturey2000 + 2 赞一个!

查看全部评分

15

主题

3

好友

807

积分

职业侠客 当前离线

Rank: 5Rank: 5

UID
880770
帖子
825
精华
0
经验
807 点
金钱
779 ¥
注册时间
2020-7-14
发表于 2024-2-24 12:44 | 显示全部楼层
辛苦了,下载学习!

0

主题

0

好友

446

积分

业余侠客 当前离线

Rank: 4

UID
273745
帖子
509
精华
0
经验
446 点
金钱
414 ¥
注册时间
2010-12-19
发表于 2024-2-24 13:31 | 显示全部楼层
谢谢分享辛苦了!!

7

主题

0

好友

122

积分

论坛游民 当前在线

Rank: 3Rank: 3

UID
827679
帖子
191
精华
0
经验
122 点
金钱
110 ¥
注册时间
2017-2-16
发表于 2024-2-24 13:38 | 显示全部楼层
谢谢分享!!!

5

主题

2

好友

978

积分
     

职业侠客 当前在线

Rank: 5Rank: 5

UID
124929
帖子
977
精华
0
经验
978 点
金钱
941 ¥
注册时间
2009-8-15
发表于 2024-2-24 13:58 | 显示全部楼层
感谢无私分享!!

43

主题

0

好友

230

积分

业余侠客 当前离线

Rank: 4

UID
1039312
帖子
190
精华
0
经验
230 点
金钱
146 ¥
注册时间
2023-4-2
发表于 2024-2-24 15:15 | 显示全部楼层
左右声道一个ADDR引脚接地另一个可以不拉高了吧

81

主题

2

好友

1491

积分

侠之大者 当前离线

Rank: 6Rank: 6

UID
897598
帖子
1384
精华
0
经验
1491 点
金钱
1290 ¥
注册时间
2021-2-4
 楼主| 发表于 2024-2-24 15:18 | 显示全部楼层
本帖最后由 mchoi518 于 2024-2-24 18:16 编辑
xandd 发表于 2024-2-24 15:15
左右声道一个ADDR引脚接地另一个可以不拉高了吧


左右声道写的值不一样,一个设置CH1,一个设置CH2,所以当然需要ADDR一个接地一个拉高



我知道了你是说高电平的不用拉高悬空也行是吧,应该可以,不过拉高又不费事,没啥不好~

99

主题

1

好友

2633

积分

罗宾汉 当前在线

Rank: 7Rank: 7Rank: 7

UID
229399
帖子
1350
精华
0
经验
2633 点
金钱
2477 ¥
注册时间
2010-8-13
发表于 2024-2-25 14:27 | 显示全部楼层
顶个贴,相当于手把手说教了。

0

主题

0

好友

150

积分
     

论坛游民 当前离线

Rank: 3Rank: 3

UID
137146
帖子
166
精华
0
经验
150 点
金钱
150 ¥
注册时间
2009-10-5
发表于 2024-2-25 15:30 | 显示全部楼层
感谢楼主无私分享,

1

主题

0

好友

30

积分

注册会员 当前离线

Rank: 2

UID
54306
帖子
27
精华
0
经验
30 点
金钱
30 ¥
注册时间
2008-9-13
发表于 2024-2-26 10:07 | 显示全部楼层
楼主 SS2590效果如何?

81

主题

2

好友

1491

积分

侠之大者 当前离线

Rank: 6Rank: 6

UID
897598
帖子
1384
精华
0
经验
1491 点
金钱
1290 ¥
注册时间
2021-2-4
 楼主| 发表于 2024-2-26 11:14 | 显示全部楼层
mnhi124 发表于 2024-2-26 10:07
楼主 SS2590效果如何?

主观的东西不好说, 只能说没什么缺点比较均衡~

还有个小优点就是它有地线脚,可以调节输出中点电压,省了个中电调节电路~

2

主题

0

好友

28

积分

注册会员 当前离线

Rank: 2

UID
1090997
帖子
26
精华
0
经验
28 点
金钱
24 ¥
注册时间
2024-2-12
发表于 2024-2-26 12:32 | 显示全部楼层
太强了,牛逼

2

主题

0

好友

28

积分

注册会员 当前离线

Rank: 2

UID
1090997
帖子
26
精华
0
经验
28 点
金钱
24 ¥
注册时间
2024-2-12
发表于 2024-2-26 12:35 | 显示全部楼层
造福我等小白

1

主题

0

好友

355

积分

业余侠客 当前离线

Rank: 4

UID
49808
帖子
355
精华
0
经验
355 点
金钱
355 ¥
注册时间
2008-8-3
发表于 2024-2-26 13:32 | 显示全部楼层
佩服!

166

主题

3

好友

3174

积分
     

罗宾汉 当前离线

Rank: 7Rank: 7Rank: 7

UID
182890
帖子
3082
精华
0
经验
3174 点
金钱
2832 ¥
注册时间
2010-3-19
发表于 2024-2-26 13:39 | 显示全部楼层
仰望一下。学习了

77

主题

1

好友

2750

积分
     

罗宾汉 当前离线

Rank: 7Rank: 7Rank: 7

UID
50056
帖子
3670
精华
0
经验
2750 点
金钱
2643 ¥
注册时间
2008-8-6
发表于 2024-2-27 19:39 | 显示全部楼层
这是高手,有理论,有实践。

16

主题

3

好友

848

积分

职业侠客 当前在线

Rank: 5Rank: 5

UID
114707
帖子
875
精华
0
经验
848 点
金钱
826 ¥
注册时间
2009-6-28
发表于 2024-2-28 01:17 | 显示全部楼层
感谢分享,辛苦了!!

0

主题

0

好友

74

积分

论坛游民 当前离线

Rank: 3Rank: 3

UID
120151
帖子
75
精华
0
经验
74 点
金钱
74 ¥
注册时间
2009-7-24
发表于 2024-2-28 10:39 | 显示全部楼层
仰望一下。学习了

4

主题

0

好友

89

积分

论坛游民 当前离线

Rank: 3Rank: 3

UID
24536
帖子
111
精华
0
经验
89 点
金钱
81 ¥
注册时间
2007-7-11
发表于 2024-2-28 11:14 | 显示全部楼层
高手啊, 谢谢无私的分享!

4

主题

0

好友

89

积分

论坛游民 当前离线

Rank: 3Rank: 3

UID
24536
帖子
111
精华
0
经验
89 点
金钱
81 ¥
注册时间
2007-7-11
发表于 2024-2-28 11:37 | 显示全部楼层
对了, 楼主的机箱很不错,有购买连接吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Powered by Discuz! X3.4

© 2001-2012 Comsenz Inc.

返回顶部