[ݳXȲέp


AVR(Atmega8) 做電腦音響控制

非8051系列的單晶片軟硬體請在此區討論(CPU介面周邊,或MICRO CHIP等....)

版主: charlesliao

AVR(Atmega8) 做電腦音響控制

文章rc993318000 發表於 週日 8月 25, 2013 3:26 pm

這想法其實拖蠻久了 只是都在忙考試而沒空去動工..
現在畢業了 在上大學前的空檔時 又想起之前做站上的TDA7294後級還沒有殼 才想起Atmega8的控制板不知道被我丟在角落丟多久了XD
而到了八月中旬 才開始用了動力去做(好吧 是我太懶XDD)
不過無奈的是 窮學生又要開學了所以完全沒錢去做更多東西._.
目前只搞出了 USB 控制 LCD顯示 音量調整 風扇轉速調整 輸入選擇 溫度感測 電源管理
原本預計的還有紅外線控制、旋轉編碼器控制
而實體按鍵輸入只做出了讀取還沒硬體去做實體控制....
----------------------------------------------------------------
現在剩下紅外線不知道怎麼做之外 還有機殼沒材料XD 其他都OK了 不知道要不要刪掉這篇文了-.-...

會選用Atmega8的原因是手邊剛好有高中時借用比賽之由去刻出的一塊小控制板 裡面韌體也能直接支援USB資料傳輸 又是DIP-28封裝的好讓有需要的人洗電路板
自己畫的電路圖、Layout如下:
MainBoard.png
ATMEGA8 SCH

MAIN.png
Atmega8 PCB


其實有想過直接用ARM去做控制 用lpc11u24(ARM Cortex-M0)這顆IC 程式燒錄可以直接用USB當作隨身碟那樣把韌體丟進去
但主要原因是開發版過於昂貴...封裝也都只有SMD 繪製電路圖、洗板會有一定的難度而作罷
不然他一顆IC只要110 相較之下Atmega8就貴上了許多....(我買好像一顆130)

但Atmega8輸出Port只有B C D PortD已經被USB占用掉兩個 所以都各只剩下6個腳能做輸出 而 PortC我拿來當ADC 剩下可憐的12隻腳能做輸出...
於是拉了張擴充版..
ExpPortSch.png
擴充板


目前的半成品
DSC_0005.jpg
半成品



Atmega8 用Avrdude 作燒錄、C語言編譯
燒錄器:
DSC_0007.jpg
AVR燒錄器

(只要支援ISP燒錄的都能用這燒錄器的樣子 像89S5X也能用)

電腦端用VB2008做控制
Program.png
電腦控制端

(Debug 用

控制板
offline.png
未連接
offline.png (20.82 KB) 被瀏覽 9350 次


圖檔
睡眠

圖檔
正常控制


Atmega8的USB控制是純軟體控制 他沒有內建USB介面 速度是跑在USB1.1 但也因為他占用掉了INT0 INT1 讓我想不出旋轉編碼器、紅外線遙控要怎做....

LCD顯示很簡單:
DSC_0006.jpg
LCD


音量調整是採用MCP410XX 數位電位器去做控制 介面採用SPI 可調段數0~255(256階) 有看過頻率響應圖 到100KHz應該是沒問題

風扇轉速控制是打算一樣採用MCP41010 去帶動LM2576做電壓調整

聲道選擇採用74HC4051*2做八聲道選擇 頻率響應應該也沒問題

溫度感測是用內建的ADC去連接LM35

電源管理是直接用SSR去控制後級的變壓器110V輸入
最後由 rc993318000 於 週一 8月 26, 2013 8:12 pm 編輯, 總共編輯了 1 次
HI~
頭像
rc993318000
 
文章: 42
註冊時間: 週二 9月 25, 2007 4:25 pm

Re: AVR(Atmega8) 做電腦音響控制

文章rc993318000 發表於 週日 8月 25, 2013 4:20 pm

不然我先採用74LS595去取代74164+74273 沒問題的話應該就能繼續做了:D
HI~
頭像
rc993318000
 
文章: 42
註冊時間: 週二 9月 25, 2007 4:25 pm

Re: AVR(Atmega8) 做電腦音響控制

文章rc993318000 發表於 週一 8月 26, 2013 1:42 am

奧 沒事了 用了74595後 程式都不用改 問題就解決了....


------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
發現74HC405X似乎隔離有點差 雜訊干擾也有點嚴重 所以乖乖用回74138+繼電器...
其他搞完了 剩下74138連繼電器沒試過0.0....IR放棄 旋轉編碼器應該OK了...
HI~
頭像
rc993318000
 
文章: 42
註冊時間: 週二 9月 25, 2007 4:25 pm

Re: AVR(Atmega8) 做電腦音響控制

文章rc993318000 發表於 週四 12月 18, 2014 11:34 pm

好久沒更新了-.-..
其實電路改很久了
目前是都做已經好了 但缺機殼跟買不到更好的數位電位器-.-....(AD5291/5292)
目前用的MCP41010有準確度問題跟電壓範圍太小...所以採用AD529X會用到+- 15V 提升輸入電壓範圍@@ 不然現在的好像輸入電壓到一定以上會進入飽和(單電源5V限制)
PDF是目前電路主架構 跟預計用到更好的數位電位器時所用的雜訊消除電路(工作原理就是過零檢測器拉 在大約等於0的時候把指令更新 比較不會有訊號抖動的問題出現)

(以下圖檔不小心傳太大張上去 就麻煩要的點開看吧...)

MCU主電路
4aQJp81_mod.gif


子電路
QDwm5PM_Mod.gif

SPI子電路 含LCM、繼電器控制 (上面那顆U2是74138)

POT
7D2po8m_mod.gif

目前還無緣的電位器電路-.-..

程式端還是照樣 不過電路上保留了很多可擴充的SPI 在想還能不能加東西上去@@ (SPI Clock頻率為FCK/2 現在選用的振盪器是12Mhz的 所以就是6Mhz)
現在能加的是可以在控制很多組數位電位器 可以用來調音值那類的
做IO控制直接拿SPI介面接74595就OK了
不過要用電腦溝通也是個問題-.-...軟體介面的USB不太好用..
HI~
頭像
rc993318000
 
文章: 42
註冊時間: 週二 9月 25, 2007 4:25 pm

Re: AVR(Atmega8) 做電腦音響控制

文章rc993318000 發表於 週四 12月 18, 2014 11:39 pm

程式碼部分
寫的應該不算好 就當參考瞜@@
代碼: 選擇全部
/*
   Pin Map
   PB0-PB5,PC1-PC4  LCD Data,EN,RS
   PC0 Power Relay
   PC1 Power Key
   PC5 ADC
   PortD Cant use 2,4
   PD0,PD1,PD3 Channel Sel,Channel Add,Enter
   PD5,PD6 Rotary encoder
   PD7 Mode Select
*/
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>  /* for sei() */
#include <util/delay.h>     /* for _delay_ms() */
#include <avr/eeprom.h>

#include <avr/pgmspace.h>   /* required by usbdrv.h */
#include "usbdrv.h"
//#include "oddebug.h"        /* This is also an example for using debug macros */
#include <string.h>
/* ------------------------------------------------------------------------- */
#define PowerPin   0
#define Key_ChSel   0
#define Key_Add      1
#define Key_Rotary1   3
#define Key_Rotary2   5
#define Key_Enter   6
#define Key_Mode   7
#define Key_Power   1   //PC1
#define Key_Repeate   1
#define ADC_Channel   5
//1s

#define SDL   3
//^ Stored data length
#define AD_Wrd   0
//if not writed then set data to 0
#define AD_Chan   1
#define AD_Res   2
#define AD_PWR   3
#define AD_TMPH   4
#define AD_TMPL   5
#define AD_DAv   6 //Data available
#define Def_Res   64
/* ------------------------------------------------------------------------- */
/* ----------------------------SPI Interface-------------------------------- */
#define SPI_Res      1
//2Byte   H:Command Byte,L:Value
//Command:x,x,C1,C0,x,x,P1,P0 (If MCP42XXX Then can use P1,P0 to Sel Channel)  C1,C0:Command,0-None,1-Write,2-ShutDown,3-None . P1,P0:Potentiometer Selections ,MCP41XXX Set to 01
#define SPI_Fan      2
#define SPI_LCD      3
#define SPI_Relay   SPI_LCD
//SPI_LCD 2 Byte   H:Unused,Unused,Relay Out Sel,Relay Out Sel,Relay In Sel,Relay In Sel,LCD E,LCD RS
//               L:LCD Data(DB7~DB0)
/* --------------------------LCD Data--------------------------------------- */
const char LCD_Blank[17]      ="                ";
const char LCD_Wel[2][17]      ={"     Welcome.   ","   Initialing.  "};
const char LCD_ShutDown[2][17]   ={"   Power Off.   ","                "};
const char LCD_Normal[2][17]   ={"Channel-I:x ,O:x","Volume: xxx/255 "};
const char LCD_Mode2[2][17]      ={"Chl-I :x ,O :x  ","Temperature:xx.x"};
#define Char_CIn   10
#define Char_COut   15
#define Char_VolS   8
#define Char_SCI   7
#define Char_SCO   13
#define Char_Temp   12
/* ------------------------------------------------------------------------- */


#define TimerCNT   162

static uchar TimerCounter;
static uchar TimerCounter2;
static uchar Timer_Flag;
static uchar LCD_Status;//0=Welcome,1=Status,2=Power Down,3=Display turn off
static uchar Mode_Select;//0-Normal,1-Channel
static char LCD_TEXT1[17];
static char LCD_TEXT2[17];
static uchar SPI_LCD_Value[2];
#define   LCD_RS   0
#define   LCD_E   1

static uchar Channel_Sel;//xxxx,out1,out0,in1,in0;
static uchar H_Channel_Sel;//For user set on Key
static uchar Channel_Set;//0 Channel In,1 Channel Out
static uchar Audio_resistor;
static uchar Power_Status;
static unsigned int Temperature;//360->36.0
static uchar AllKeyWait;//1s count down 1
static uchar RotKeyWait;//4ms count down 1 for encoder


/* ------------------------------------------------------------------------- */
void PowerIO(uchar);
static uchar PKeyWait;//count down  =0 means the key is vailed  ,1s count down 1
/* ------------------------------------------------------------------------- */
void WriteData(void);
void ReadData(void);
/* ------------------------------------------------------------------------- */
void Timer_1S(void);
void Timer_4ms(void);
/* ------------------------------------------------------------------------- */
void INT1_init(void);
void lcd_init(void);
void ADC_init(void);
void Timer_init(void);
void SPI_MasterInit(void);
/* ------------------------------------------------------------------------- */
void lcd_status_update(void);
void lcd_command(uchar value);
void lcd_data(uchar value);
void lcd_update(void);
void LCD_Clear(void);
/* ------------------------------------------------------------------------- */
void WriteSPI(uchar ,uchar *,uchar);
void UpdateRes(uchar,uchar);
void ResShutDown(uchar);
void UpdateChannel(void);


/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */

PROGMEM const char usbHidReportDescriptor[22] = {    /* USB report descriptor */
    0x06, 0x00, 0xff,              // USAGE_PAGE (Generic Desktop)
    0x09, 0x01,                    // USAGE (Vendor Usage 1)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x10,                    //   REPORT_COUNT (16)
    0x09, 0x00,                    //   USAGE (Undefined)
    0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
    0xc0                           // END_COLLECTION
};
/* Since we define only one feature report, we don't use report-IDs (which
* would be the first byte of the report). The entire report consists of 128
* opaque data bytes.
*/

/* The following variables store the status of the current data transfer */
static uchar    currentAddress;
static uchar    bytesRemaining;

/* ------------------------------------------------------------------------- */

/* usbFunctionRead() is called when the host requests a chunk of data from
* the device. For more information see the documentation in usbdrv/usbdrv.h.
*/
uchar   usbFunctionRead(uchar *data, uchar len)
{
    if(len > bytesRemaining)
        len = bytesRemaining;
   if(currentAddress == 0){
      *(data)            = 0;
      *(data+AD_Chan)        = Channel_Sel;
      *(data+AD_Res)      = Audio_resistor;
      *(data+AD_PWR)       = Power_Status;
      *(data+AD_TMPH)    = (Temperature/10) &0xff;
      *(data+AD_TMPL)    = (Temperature%10) &0xff;
      *(data+AD_DAv)       = 1;
   }
    currentAddress += len;
    bytesRemaining -= len;
    return len;
}
uchar   usbFunctionWrite(uchar *data, uchar len)
{
    if(bytesRemaining == 0)
        return 1;               /* end of transfer */
    if(len > bytesRemaining)
        len = bytesRemaining;
   if(currentAddress == 0)
   {
      uchar Old_PowerStatus=Power_Status;
      Power_Status   =*(data+AD_PWR);
      if(Power_Status)
      {
         if(Old_PowerStatus)
         {
            Channel_Sel      =*(data+AD_Chan);
            Audio_resistor   =*(data+AD_Res);
            UpdateRes(SPI_Res,Audio_resistor);
            UpdateChannel();
            WriteData();
         }
         else
         {
            ReadData();
            UpdateRes(SPI_Res,Audio_resistor);
            UpdateChannel();
            LCD_Status = 1;
            PowerIO(1);
         }
      }
      else
      {
         if(Old_PowerStatus)
         {
            LCD_Status = 2;
            TimerCounter2 = 0;
         }
      }
      lcd_status_update();
   }
    currentAddress += len;
    bytesRemaining -= len;
    return bytesRemaining == 0; /* return 1 if this was the last chunk */
}

/* ------------------------------------------------------------------------- */

usbMsgLen_t usbFunctionSetup(uchar data[8])
{
   usbRequest_t    *rq = (void *)data;
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){    /* HID class request */
        if(rq->bRequest == USBRQ_HID_GET_REPORT){  /* wValue: ReportType (highbyte), ReportID (lowbyte) */
            /* since we have only one report type, we can ignore the report-ID */
            bytesRemaining = 8;
            currentAddress = 0;
            return USB_NO_MSG;  /* use usbFunctionRead() to obtain data */
        }else if(rq->bRequest == USBRQ_HID_SET_REPORT){
            /* since we have only one report type, we can ignore the report-ID */
            bytesRemaining = 8;
            currentAddress = 0;
            return USB_NO_MSG;  /* use usbFunctionWrite() to receive data from host */
        }
    }else{
        /* ignore vendor type requests, we don't use any */
    }
    return 0;
}


/* -----------------------------Init---------------------------------------- */
void lcd_init(void){
   lcd_command(60);
   _delay_us(300);
   lcd_command(1);
   _delay_us(300);
   lcd_command(2);
   _delay_us(300);
   lcd_command(6);
   _delay_us(300);
   lcd_command(8);//turn off display and cursor  ,12 >turn on
   _delay_us(300);
   lcd_command(12);
   _delay_us(300);
   lcd_command(20);
   _delay_us(300);
   LCD_Status=0;
   Mode_Select=0;
   strncpy(LCD_TEXT1,LCD_Blank,16);
   strncpy(LCD_TEXT2,LCD_Blank,16);
}
void INT1_init(void)
{
   MCUCR |= (1<<ISC11) |(0<<ISC10);//The failling edge of INT1 generates an interrupt request
   GICR |=(1<<INT1);//Interrupt Request 1 Enable
   RotKeyWait = 0;
}
void Timer_init(void){
   TIMSK |= (1 << TOIE0);
   TCCR0 |= (1 << CS02);
    // set prescaler to 256 and start the timer
   TCNT0 = TimerCNT;
   TimerCounter = 0;
}
void ADC_init()
{
    ADMUX    = (1<<REFS1)|(1<<REFS0)|(ADC_Channel&0x07);// VREF = 2.56 ,ADC0
   ADCSRA   = (1<<ADEN)|(1<<ADFR);//Set to free mode
   ADCSRA   |=(1<<ADSC);//start adc
}
void SPI_MasterInit(void)
{
   /* Enable SPI, Master, set clock rate fck/2 ,MSB First , SCK is Low when idle*/
   SPCR = (1<<SPE)|(1<<MSTR)|(0<<SPR1)|(0<<SPR0);
   SPSR = (1<<SPI2X);
}
/* ------------------------------------------------------------------------- */
void WriteData(void)
{
   eeprom_write_byte((void*)AD_Wrd,0);
   eeprom_write_byte((void*)AD_Chan,Channel_Sel);
   eeprom_write_byte((void*)AD_Res,Audio_resistor);
}
void ReadData(void)
{
   Channel_Sel      =   eeprom_read_byte((void*)AD_Chan);
   Audio_resistor   =   eeprom_read_byte((void*)AD_Res);
}
/* -----------------------------Timer----------------------------------------- */
void Timer_1S(void)
{
   if(LCD_Status==2)
   {
      LCD_Status = 3;
      Mode_Select = 0;
      PowerIO(0);
      lcd_status_update();
   }
   if(PKeyWait>0)
      PKeyWait--;
   if(AllKeyWait>0)
      AllKeyWait--;
}
void Timer_4ms(void)
{
   Timer_Flag=0;
   TimerCounter2++;
   if(ADCSRA&(1<<ADIF))
   {
      Temperature=((((ADCH*256)+ADCL-30)*5)/2);
      //Temperature=(Temperature<<8)+ADCL;
   }
   if(TimerCounter2>=200)
   {
      TimerCounter2=0;
      Timer_1S();
   }
   if(RotKeyWait>0)
   {
      RotKeyWait--;
   }
}


ISR (TIMER0_OVF_vect)
{//every 2 ms
   TimerCounter++;
   if(TimerCounter>=2)
   {
      Timer_Flag=1;
      TimerCounter=0;
   }
   TCNT0 += TimerCNT;
}

/* -----------------------------LCD----------------------------------------- */
//SPI_LCD 2 Byte   H:Unused,Unused,Relay Out Sel,Relay Out Sel,Relay In Sel,Relay In Sel,LCD E,LCD RS
//               L:LCD Data(DB7~DB0)
void lcd_command(uchar value)
{
   //RS=0
   SPI_LCD_Value[1]=(Channel_Sel&0x0f)<<2;
   SPI_LCD_Value[0]=0x00;
   WriteSPI(SPI_LCD,SPI_LCD_Value,2);//Clear RS,EN
   SPI_LCD_Value[1]|=1<<LCD_E;//Set EN
   SPI_LCD_Value[0]=value;
   WriteSPI(SPI_LCD,SPI_LCD_Value,2);//WriteData
   SPI_LCD_Value[1]=(Channel_Sel&0x0f)<<2;
   SPI_LCD_Value[0]=0x00;
   _delay_us(100);
   WriteSPI(SPI_LCD,SPI_LCD_Value,2);//Clear EN
}
void lcd_data(uchar value)
{   
   //RS=1
   SPI_LCD_Value[1]=(Channel_Sel&0x0f)<<2;
   SPI_LCD_Value[0]=0x00;
   WriteSPI(SPI_LCD,SPI_LCD_Value,2);//Clear RS,EN
   SPI_LCD_Value[1]|=(1<<LCD_E)|(1<<LCD_RS);//Set EN,RS
   SPI_LCD_Value[0]=value;
   WriteSPI(SPI_LCD,SPI_LCD_Value,2);//WriteData
   SPI_LCD_Value[1]=(Channel_Sel&0x0f)<<2;
   SPI_LCD_Value[0]=0x00;
   _delay_us(40);
   WriteSPI(SPI_LCD,SPI_LCD_Value,2);//Clear EN
}
void lcd_status_update(void)
{   
   static uchar tempValue;
   switch(LCD_Status)
   {
      case 0:
         strncpy(LCD_TEXT1,LCD_Wel[0],16);
         strncpy(LCD_TEXT2,LCD_Wel[1],16);
         break;
      case 1:
         if(Mode_Select==0)
         {
            strncpy(LCD_TEXT1,LCD_Normal[0],16);
            strncpy(LCD_TEXT2,LCD_Normal[1],16);
            LCD_TEXT1[Char_CIn]=(Channel_Sel&0x03)+'0';
            LCD_TEXT1[Char_COut]=((Channel_Sel>>2)&0x03)+'0';
            tempValue = Audio_resistor;
            if(Audio_resistor>=100)
            {
               LCD_TEXT2[Char_VolS]=tempValue/100 + '0';
               LCD_TEXT2[Char_VolS+1]='0';
            }
            else
               LCD_TEXT2[Char_VolS]=' ';
            tempValue%=100;
            if(Audio_resistor>=10)
               LCD_TEXT2[Char_VolS+1]=tempValue/10 + '0';
            else
               LCD_TEXT2[Char_VolS+1]=' ';
            LCD_TEXT2[Char_VolS+2]=tempValue%10 + '0';
         }
         else
         {
            strncpy(LCD_TEXT1,LCD_Mode2[0],16);
            strncpy(LCD_TEXT2,LCD_Mode2[1],16);
            if(Channel_Set==0)
            {
               LCD_TEXT1[Char_SCI-2]='.';
               LCD_TEXT1[Char_SCO-2]=' ';
            }
            else
            {
               LCD_TEXT1[Char_SCI-2]=' ';
               LCD_TEXT1[Char_SCO-2]='.';
            }
            LCD_TEXT1[Char_SCI]=(H_Channel_Sel&0x03)+'0';
            LCD_TEXT1[Char_SCO]=((H_Channel_Sel>>2)&0x03)+'0';
            LCD_TEXT2[Char_Temp]=(Temperature/100)+'0';
            LCD_TEXT2[Char_Temp+1]=((Temperature%100)/10)+'0';
            LCD_TEXT2[Char_Temp+3]=((Temperature%10))+'0';
         }
         break;
      case 2:
         strncpy(LCD_TEXT1,LCD_ShutDown[0],16);
         strncpy(LCD_TEXT2,LCD_ShutDown[1],16);
         WriteData();
         UpdateRes(SPI_Res,0);
         Channel_Sel = 0;
         UpdateChannel();
         ResShutDown(SPI_Res);
         break;
      case 3:
         strncpy(LCD_TEXT1,LCD_Blank,16);
         strncpy(LCD_TEXT2,LCD_Blank,16);
         break;
      default:
         break;
   }
   lcd_update();
}
void lcd_update(void)
{
   uchar i;
   lcd_command(0x80);
   for(i=0;i<16;i++)
   {
      lcd_data(LCD_TEXT1[i]);   
   }
   lcd_command(0xC0);
   for(i=0;i<16;i++)
   {
      lcd_data(LCD_TEXT2[i]);
   }
}
void LCD_Clear(void)
{
   lcd_command(1);
   strncpy(LCD_TEXT1,LCD_Blank,16);
   strncpy(LCD_TEXT2,LCD_Blank,16);
}
/* -----------------------------INT1---------------------------------------- */
ISR (INT1_vect)//PD3(Int1),PD5 Rotary encoder
{
   if(RotKeyWait==0 && Power_Status==1)
   {
      if((PIND&(1<<Key_Rotary2))!=0)
      {
         if(Audio_resistor<255)
            Audio_resistor++;
      }
      else
      {
         if(Audio_resistor>0)
            Audio_resistor--;
      }
      UpdateRes(SPI_Res,Audio_resistor);
      lcd_status_update();
      WriteData();
      RotKeyWait = 2;
   }
}
/* -----------------------------SPI----------------------------------------- */
void WriteSPI(uchar chip,uchar *data,uchar len)//From MSB to LSB
{
   uchar i;
   if(len>0&&chip<8)
   {
      PORTB&= 0xf8;
      PORTB|= chip&0x07;
      for(i=len;i>0;i--)
      {
         SPDR = data[i-1];//Start trans
         while((SPSR & (1<<SPIF)));
      }
   }
   PORTB &= 0xf8;
}
void UpdateRes(uchar spinum,uchar value)
{
   static uchar sendbyte[2];
   Audio_resistor = value;
   //2Byte   H:Command Byte,L:Value
   //Command:x,x,C1,C0,x,x,P1,P0 (If MCP42XXX Then can use P1,P0 to Sel Channel)  C1,C0:Command,0-None,1-Write,2-ShutDown,3-None . P1,P0:Potentiometer Selections ,MCP41XXX Set to 01
   sendbyte[1] = 0x13;
   sendbyte[0] = value;
   WriteSPI(spinum,sendbyte,2);
}
void ResShutDown(uchar spinum)
{
   uchar sendbyte[2];
   sendbyte[1] = 0x23;
   sendbyte[0] = 0;
   WriteSPI(spinum,sendbyte,2);
}
void UpdateChannel(void)
{
   SPI_LCD_Value[1]=(SPI_LCD_Value[1]&0x3C)|((Channel_Sel&0x0f)<<2);
   WriteSPI(SPI_LCD,SPI_LCD_Value,2);
}
/* ------------------------------------------------------------------------- */
void PowerIO(uchar stat)
{
   stat&=1;
   PORTC=(PORTC&(0xff-(1<<PowerPin)))|(stat<<PowerPin);
   Power_Status=stat;
}

int main(void)
{   
   uchar   i;
    wdt_enable(WDTO_1S);
    /* Even if you don't use the watchdog, turn it off here. On newer devices,
     * the status of the watchdog (on/off, period) is PRESERVED OVER RESET!
     */
               // ---------------------------------------------------------
                   //   DDB7   DDB6   DDB5   DDB4   DDB3   DDB2   DDB1   DDB0
   DDRB = 0x3f;    //    0      0      1      1      1      1      1      1
                   //    x      x     out    out    out    out    out    out
               // ---------------------------------------------------------
                    //  PORTB7 PORTB6 PORTB5 PORTB4 PORTB3 PORTB2 PORTB1 PORTB0
   PORTB =0x00;    //    0      0      0      0      0      0      0      0
               // ---------------------------------------------------------

               // ---------------------------------------------------------
                //    -     DDC6   DDC5   DDC4   DDC3   DDC2   DDC1   DDC0
   DDRC = 0x1d;    //    0      0      0      1      1      1      0      1 
               //  (Read)   in     in    out    out    out     in    out                     
               // ---------------------------------------------------------
                    //    -    PORTC6 PORTC5 PORTC4 PORTC3 PORTC2 PORTC1 PORTC0                     
    PORTC =0x02;    //    0      0      0      0      0      0      1      0
               // ---------------------------------------------------------

                // ---------------------------------------------------------
                   //   DDD7   DDD6   DDD5   DDD4   DDD3   DDD2   DDD1   DDD0
   DDRD = 0x00;    //    0      0      0      0      0      0      0      0   
               //    in     in     in    D-      in     D+     in     in
               // ---------------------------------------------------------
                   //  PORTD7 PORTD6 PORTD5 PORTD4 PORTD3 PORTD2 PORTD1 PORTD0
   PORTD =0xeb;    //    1      1      1      0      1      0      1      1 
               // ---------------------------------------------------------
   
   RotKeyWait = 0xff;
    usbInit();
   SPI_MasterInit();
    usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */
   i = 0;
    while(--i){             /* fake USB disconnect for > 250 ms */
        wdt_reset();
        _delay_ms(1);
    }
    usbDeviceConnect();
   Timer_init();
   ADC_init();
   INT1_init();
   lcd_init();
   lcd_status_update();
    sei();// You can't use other interrupt cause of timing
   PowerIO(1);//Power UP
   
   uchar setting_status=eeprom_read_byte((void*)AD_Wrd);
   if(setting_status!=0)//First Time start up
   {
      Channel_Sel      =   0;
      Audio_resistor   =   Def_Res;
      WriteData();
   }
   else
   {
      Channel_Sel      =   eeprom_read_byte((void*)AD_Chan);
      Audio_resistor   =   eeprom_read_byte((void*)AD_Res);
   }
   UpdateRes(SPI_Res,Audio_resistor);
   UpdateChannel();
   
   LCD_Status = 1;
   lcd_status_update();
   /*
   #define Key_ChSel   0
   #define Key_Add      1
   #define Key_Rotary1   3
   #define Key_Rotary2   5
   #define Key_Enter   6
   #define Key_Mode   7
   0 1  6 7
   11000011
   */
    while(1)            /* main event loop */
   {
        wdt_reset();
        usbPoll();
      if((PINC&(1<<Key_Power))==0 && (PKeyWait==0))
      {
         PKeyWait = 2;
         if(Power_Status == 1)
         {
            LCD_Status = 2;
         }
         else
         {
            ReadData();
            UpdateRes(SPI_Res,Audio_resistor);
            UpdateChannel();
            LCD_Status = 1;
            PowerIO(1);
         }
         TimerCounter2 = 0;
         lcd_status_update();
      }
      if((PIND&0xc3)!=0xc3 &&  Power_Status==1)
      {
         if(AllKeyWait==0)
         {
            AllKeyWait=Key_Repeate;
            if((PIND&(1<<Key_Mode))==0)
            {
               Mode_Select=1-Mode_Select;
               H_Channel_Sel = Channel_Sel;
               Channel_Set = 0;
            }
            else if((PIND&(1<<Key_Add))==0)
            {
               if(Mode_Select==1)
               {
                  if(Channel_Set==0)//input
                  {
                     i = H_Channel_Sel & 0x03;
                     i=(i+1)%4;
                     H_Channel_Sel = (H_Channel_Sel&0xfc)|i;
                  }
                  else//output
                  {
                     i = (H_Channel_Sel>>2) & 0x03;
                     i=(i+1)%4;
                     H_Channel_Sel = (H_Channel_Sel&0xf3)|(i<<2);
                  }
               }
            }
            else if((PIND&(1<<Key_ChSel))==0)
            {
               if(Mode_Select==1)
               {
                  Channel_Set = 1 - Channel_Set;
               }
            }
            else if((PIND&(1<<Key_Enter))==0)
            {
               if(Mode_Select==1)
               {
                  Channel_Sel = H_Channel_Sel;
                  UpdateChannel();
                  WriteData();
               }
            }
         }
         //TimerCounter2 = 0;
         lcd_status_update();
      }
      if(Timer_Flag==1)
      {
         Timer_4ms();
      }
    }
    return 0;
}

/* ------------------------------------------------------------------------- */

HI~
頭像
rc993318000
 
文章: 42
註冊時間: 週二 9月 25, 2007 4:25 pm

Re: AVR(Atmega8) 做電腦音響控制

文章oldhan 發表於 週四 12月 25, 2014 2:56 pm

做的不錯,為何不用專門的音量控制 IC CS3310/PGA2311?
4051 的隔離也不如繼電器要好,
ATMEGA328 現在便宜多了,
焊接好的 ARDUINO ProMini 67十塊台幣可買到.
oldhan
 
文章: 202
註冊時間: 週日 4月 22, 2007 2:49 pm
來自: 台北縣

Re: AVR(Atmega8) 做電腦音響控制

文章rc993318000 發表於 週四 12月 25, 2014 9:40 pm

會想到做這個最主要原因就是手上拿到了一塊Atmega8的板子 想來練練MCU的程式
於是就開始想這塊板子能幹嘛 就無聊跑來寫這東西了~
不然真的要用USB介面不會採用軟體USB去跑 應該也會是用ATmega8U2 這種自帶USB Interface的IC
軟體USB限制很多...像是幾乎不可以用中斷、每次USB輪詢時間間隔不能太常 不然電腦端就把你強制斷線了...囧
(不然如果我有FPGA、ARM這種開發版我可能早就跳槽過去玩了XD)
不過真的要玩USB也很難 現在都是很偷懶的用HID介面...不然光驅動我可能就掛掉了Orz

4051我最開始測完就放棄了..現在電路是用74139 用兩組2對4解碼選擇繼電器做輸入輸出選擇
至於數位電位器的話....其實我是不知道能用什麼IC拉XD
不過我是在想 現在做出來都是B類線性可變 用軟體模擬A類會有比較好的效果嗎@@
HI~
頭像
rc993318000
 
文章: 42
註冊時間: 週二 9月 25, 2007 4:25 pm


回到 其他類單晶片--相關的軟硬體討論區

誰在線上

正在瀏覽這個版面的使用者:沒有註冊會員 和 6 位訪客