痞酷網_PIGOO

 找回密碼
 立即註冊
!!! [系統偵測到廣告阻擋軟體] !!!

如果您覺得痞酷網對您有些許幫助,或者您認同痞酷網的理想,

那麼希望您將痞酷網設定為白名單.

並請在上論壇的時候,動動您的手指,用行動支持我們.

謝謝!
查看: 2273|回復: 7

AD7840 DAC 轉換問題求助!!

[複製鏈接]
發表於 2019-3-10 16:42:04 | 顯示全部樓層 |閱讀模式
各位同好先進們,我目前遇到一個問題就是 我從回收場取得一片 PLC的 DAC 板子(不知好壞,沒有線路) 只見到裡面的 AD7840 想到他的14bit DAC 就興奮,於是花了許多時間把線路的局部給畫了下來, 然後想想如何使用 ARDUINO 驅動他,終極目標就是想用他來當作"數位電源供應"的前端,目前,問題在於我的電路有四個DAC 而我現在只使用兩個DAC,而卻 輸出 1 時候,輸出 2 "就沒有了",(當我輸出 2 時候,輸出 1 也就沒有了!) 這電路控制使用 光耦合驅動  Data1Pin  DataPin2 SyncPin ClockPin ... 我需要解決就是 兩個輸出都可以同時出現!!

DSC09493.JPG

DSC09497.JPG

DSC09498.JPG

DSC09494.JPG

DSC09495.JPG

DSC09496.JPG

線路圖

PLCDAC.jpg


程式內容如下:
  1. //MERGE ENCODER AND LCM DISPLAY
  2. static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
  3. static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
  4. volatile byte aFlag = 0;
  5. volatile byte bFlag = 0;
  6. volatile long encoderPos = 0;
  7. volatile long oldEncPos = 0;
  8. volatile byte reading = 0;
  9. const int EncoderSW = 4;//Enter SW
  10. //-------------upper is encoder ------------------------------

  11. //Define 74HC595 Connections with arduio
  12. const int Latch=5; //LCM
  13. const int Data=6;  //LCM
  14. const int Clock=7; //LCM
  15. const int OEnPin=8;//output enable OPA
  16. const int SyncPin=9;//AD7840
  17. const int ClockPin=10;//AD7840
  18. const int SDataPin=11;//AD7840
  19. const int SDataPin2=12;//AD78402

  20. const byte Volt_in =A0;
  21. const byte Current_in = A3;

  22. // const int Led=13;//Led on off
  23. void LCDinit(void);
  24. void LCDSendByte(char d,char RS);
  25. void LCDPrint(char Line,char string[40]);//------------------------------------
  26. String msg;
  27. boolean flagread = false;//rs232 updata
  28. String msgdisplay;
  29. char msgbuf[20];//rs232 read buffer
  30. char Echar_Array[40];//char array 15 character ------------------------------
  31. char msgdisplay_Array[40];//display setting data  --------------------------------
  32. char V2_Array[5];
  33. int Echar_length;
  34. int oldstringlength;
  35. String Echar_str;
  36. long Echar;
  37. long SetData;//form rs232 PC
  38. boolean flag1st = true;
  39. int SWcount;
  40. int Volt_value =0;
  41. int Curr_value =0;
  42. int Volt_value2 =0;
  43. int Curr_value2 =0;
  44. int old_Volt_value;
  45. int old_Curr_value;
  46. boolean encoder_change_flag = false;
  47. boolean Encoder_flag = false;
  48. int Menu_curs;
  49. int Old_Menu_curs;
  50. static int display_time_count =0;
  51. int Level0 =0;
  52. boolean init_flag = false;
  53. boolean Display_flag;
  54. int old_value;
  55. int Volt_oldstringlength;
  56. void setup() {
  57.   pinMode(pinA, INPUT_PULLUP); // set pinA as an input _PULLUP
  58.   pinMode(pinB, INPUT_PULLUP); // set pinB as an input _PULLUP
  59.   attachInterrupt(0,PinA,RISING); // set an interrupt on PinA
  60.   attachInterrupt(1,PinB,RISING); // set an interrupt on PinB
  61.   Serial.begin(38400); // start the serial monitor link
  62. //--------------------------------   encoder --------------------------
  63.    pinMode(EncoderSW, INPUT_PULLUP);         
  64. //------------------------------^^^-- encoder --^^^----------------------------------
  65. //-----------------vvv-LCM -vvv-----------------
  66.   pinMode(Data, OUTPUT);
  67.   pinMode(Clock, OUTPUT);
  68.   pinMode(Latch, OUTPUT);  
  69. //----------AD7840 ------------------
  70. pinMode(ClockPin,OUTPUT);//AD7840
  71. pinMode(SDataPin,OUTPUT);//AD7840
  72.   pinMode(SDataPin2,OUTPUT);//AD7840
  73. pinMode(SyncPin,OUTPUT);//AD7840
  74. pinMode(OEnPin,OUTPUT);//OPA Vss
  75. // pinMode(Volt_in,INPUT);//analog input
  76. // pinMode(Current_in,INPUT);//analog input  
  77. //------------output initial ------------
  78. digitalWrite(OEnPin,HIGH);
  79. digitalWrite(SyncPin,HIGH);
  80.   digitalWrite(ClockPin,HIGH);
  81.   LCDinit();  //initalize LCD in 4-bit mode
  82.   LCDPrint(0,"> Set Voltage Hello");
  83.   LCDPrint(1,"> Set Current start");
  84.   LCDPrintString(0,20,"> Voltage Out  2019");
  85.   LCDPrintString(1,20,"> Current Out Feb-28");
  86. }

  87. void loop() {
  88.          while (!digitalRead(EncoderSW))  
  89.   while(1)
  90.   {
  91.      digitalWrite(OEnPin,LOW);
  92.     GetEncoder();
  93.      encoderPos = 0;
  94.     Menu_curs += Echar;
  95.    if(Old_Menu_curs != Menu_curs)
  96.    {
  97.     Old_Menu_curs = Menu_curs;
  98.     Display_flag = true;
  99.    }  
  100.    
  101.     if((Menu_curs >4) ||(Menu_curs <0) )
  102.     {
  103.       Menu_curs =0;
  104.       init_flag = true;
  105.     }
  106.    
  107.   switch (Menu_curs)
  108.   {
  109.     case 0:
  110.              if(Display_flag)
  111.              {
  112.                LCDPrintString(0,0, "^ Set Voltage ");
  113.                LCDWriteChar(0,0,'^');
  114.                LCDWriteChar(1,0,'>');
  115.                LCDWriteChar(0,20,'>');
  116.                LCDWriteChar(1,20,'>');
  117.                Display_flag = false;
  118.              }
  119.             Level0 = Read_Encoder_SW();//Read encoder sw to Level0
  120.             if(Level0 ==1)
  121.             {
  122.               boolean Level1=true;
  123.               LCDWriteChar(0,1,'>');
  124.               while(Level1)
  125.                 {
  126.                  GetEncoder();
  127.                  Volt_value +=Echar;
  128.                  encoderPos = 0;
  129.                  if(Volt_value != old_value)
  130.                    {
  131.                     old_value = Volt_value;
  132.                     boolean UpdateLCD_flag = true;                  
  133.                     if(UpdateLCD_flag)
  134.                     {
  135.                       String V2_str = String(Volt_value);
  136.                       V2_str.toCharArray(V2_Array,5);
  137.                       LCDPrintString(0,14,V2_Array);
  138.                       int Echar_length= V2_str.length();                     
  139.                      if (oldstringlength != Echar_length)
  140.                          {
  141.                            oldstringlength= Echar_length;
  142.                            LCDPrintString(0,13,"      ");//clean some digit  
  143.                            LCDPrintString(0,14,V2_Array);//------------------                           
  144.                          }
  145.                            Echar=0;
  146.                            int Volt_value100 = Volt_value * 231;//MAX IS 163
  147.                            AD7840driv(SDataPin,Volt_value100);
  148.                            UpdateLCD_flag = false;
  149.                      }              
  150.                     }
  151.                      int Level0level1= Read_Encoder_SW();
  152.                      if (Level0level1 ==1)
  153.                         {
  154.                           Level0 =0;
  155.                           Level1 = false;
  156.                           LCDWriteChar(0,1,' ');
  157.                         }   
  158.                    }
  159.                 }            
  160.              break;
  161.    
  162.     case 1:
  163.              if(Display_flag)
  164.              {
  165.                LCDPrintString(1,0, "^ Set Current ");
  166.                LCDWriteChar(0,0,'>');
  167.                LCDWriteChar(1,0,'^');
  168.                LCDWriteChar(0,20,'>');
  169.                LCDWriteChar(1,20,'>');
  170.                Display_flag = false;
  171.              }
  172.             Level0 = Read_Encoder_SW();//Read encoder sw to Level0
  173.             if(Level0 ==1)
  174.             {
  175.               boolean Level1=true;
  176.               LCDWriteChar(1,1,'>');
  177.               while(Level1)
  178.                 {
  179.                  GetEncoder();
  180.                  Curr_value +=Echar;
  181.                  encoderPos = 0;
  182.                  if(Curr_value != old_value)
  183.                    {
  184.                     old_value = Curr_value;
  185.                     boolean UpdateLCD_flag = true;
  186.                    if(UpdateLCD_flag)
  187.                      {
  188.                       String V2_str = String(Curr_value);
  189.                       V2_str.toCharArray(V2_Array,5);
  190.                       LCDPrintString(1,14,V2_Array);
  191.                       int Echar_length= V2_str.length();                     
  192.                      if (oldstringlength != Echar_length)
  193.                          {
  194.                            oldstringlength= Echar_length;
  195.                            LCDPrintString(1,13,"      ");//clean some digit  
  196.                            LCDPrintString(1,14,V2_Array);//------------------                           
  197.                          }
  198.                            Echar=0;
  199.                            int Curr_value100 = Curr_value *232;
  200.                            AD7840driv(SDataPin2,Curr_value100);
  201.                            UpdateLCD_flag = false;
  202.                      }              
  203.                     }
  204.                       int Level0level1= Read_Encoder_SW();
  205.                      if (Level0level1 ==1)
  206.                         {
  207.                           Level0 =0;
  208.                           Level1 = false;
  209.                           LCDWriteChar(1,1,' ');
  210.                         }   
  211.                    }
  212.                 }
  213.              break;
  214.         case 2:
  215.             if(Display_flag)
  216.              {
  217.                LCDPrintString(0,20, "^ Voltage Out");
  218.                LCDWriteChar(0,0,'>');
  219.                LCDWriteChar(1,0,'>');
  220.                LCDWriteChar(0,20,'^');
  221.                LCDWriteChar(1,20,'>');
  222.                Display_flag = false;
  223.              }
  224.             Level0 = Read_Encoder_SW();//Read encoder sw to Level0
  225.             if(Level0 ==1)
  226.             {
  227.               boolean Level1=true;
  228.               LCDWriteChar(0,21,'>');
  229.               while(Level1)
  230.                 {
  231.                 // GetEncoder();
  232.                  Volt_value2 =analogRead(Volt_in);
  233.                //  encoderPos = 0;
  234.                  if(Volt_value2 != old_Volt_value)
  235.                    {
  236.                     old_Volt_value = Volt_value2;
  237.                     boolean UpdateLCD_flag = true;                  
  238.                     if(UpdateLCD_flag)
  239.                     {
  240.                       String V2_str = String(Volt_value2);
  241.                       V2_str.toCharArray(V2_Array,5);
  242.                       LCDPrintString(0,34,V2_Array);
  243.                       int Echar_length= V2_str.length();                     
  244.                      if (oldstringlength != Echar_length)
  245.                          {
  246.                            oldstringlength= Echar_length;
  247.                            LCDPrintString(0,33,"       ");//clean some digit                           
  248.                          }
  249.                            Echar=0;
  250.                          //  AD7840driv(SDataPin,Volt_value2);
  251.                            UpdateLCD_flag = false;
  252.                      }              
  253.                     }
  254.                       int Level0level1= Read_Encoder_SW();
  255.                      if (Level0level1 ==1)
  256.                         {
  257.                           Level0 =0;
  258.                           Level1 = false;
  259.                           LCDWriteChar(0,21,' ');
  260.                         }   
  261.                    }
  262.                 }              
  263.              break;
  264.         case 3:
  265.             if(Display_flag)
  266.              {
  267.                LCDPrintString(1,20, "^ Current Out");
  268.                LCDWriteChar(0,0,'>');
  269.                LCDWriteChar(1,0,'>');
  270.                LCDWriteChar(0,20,'>');
  271.                LCDWriteChar(1,20,'^');
  272.                Display_flag = false;
  273.              }
  274.             Level0 = Read_Encoder_SW();//Read encoder sw to Level0
  275.             if(Level0 ==1)
  276.             {
  277.               boolean Level1=true;
  278.               LCDWriteChar(1,21,'>');
  279.               while(Level1)
  280.                 {
  281.                 // GetEncoder();
  282.                  Curr_value2 =analogRead(Current_in);

  283.                //  encoderPos = 0;
  284.                  if(Curr_value2 != old_Curr_value)
  285.                    {
  286.                     old_Curr_value = Curr_value2;
  287.                     boolean UpdateLCD_flag = true;                  
  288.                     if(UpdateLCD_flag)
  289.                     {
  290.                       String V2_str = String(Curr_value2);
  291.                       V2_str.toCharArray(V2_Array,5);
  292.                       LCDPrintString(1,34,V2_Array);
  293.                       int Echar_length= V2_str.length();                     
  294.                      if (oldstringlength != Echar_length)
  295.                          {
  296.                            oldstringlength= Echar_length;
  297.                            LCDPrintString(1,33,"       ");//clean some digit                           
  298.                          }
  299.                            Echar=0;
  300.                          //  AD7840driv(SDataPin,Volt_value2);
  301.                            UpdateLCD_flag = false;
  302.                      }              
  303.                     }
  304.                       int Level0level1= Read_Encoder_SW();
  305.                      if (Level0level1 ==1)
  306.                         {
  307.                           Level0 =0;
  308.                           Level1 = false;
  309.                           LCDWriteChar(1,21,' ');
  310.                         }   
  311.                    }
  312.                 }               
  313.              break;
  314.     case 4: //display screen purpose
  315.                  if(Display_flag)
  316.              {
  317.                LCDclean();
  318.                LCDPrintString(0,0, "> Set Voltage");
  319.                LCDPrintString(1,0, "> Set Current");
  320.                LCDPrintString(0,20,"> Voltage Out");
  321.                LCDPrintString(1,20,"> Current Out");
  322.                LCDWriteChar(0,0,'*');
  323.                LCDWriteChar(1,0,'*');
  324.                LCDWriteChar(0,20,'*');
  325.                LCDWriteChar(1,20,'*');
  326.                Display_flag = false;
  327.              }     
  328.                       String V2_str = String(Volt_value);
  329.                       V2_str.toCharArray(V2_Array,5);
  330.                       LCDPrintString(0,14,V2_Array);
  331.                        V2_str = String(Curr_value);
  332.                       V2_str.toCharArray(V2_Array,5);
  333.                       LCDPrintString(1,14,V2_Array);
  334.                        Volt_value2 =analogRead(Volt_in);
  335.                        V2_str = String(Volt_value2);
  336.                       V2_str.toCharArray(V2_Array,5);
  337.                       LCDPrintString(0,34,V2_Array);
  338.                       int Echar_length= V2_str.length();                  
  339.                      if (Volt_oldstringlength != Echar_length)
  340.                          {
  341.                            Volt_oldstringlength= Echar_length;                     
  342.                            LCDPrintString(0,33,"       ");//clean some digit                           
  343.                          }                     
  344.                       Curr_value2 =analogRead(Current_in);
  345.                       V2_str = String(Curr_value2);
  346.                       V2_str.toCharArray(V2_Array,5);
  347.                       LCDPrintString(1,34,V2_Array);
  348.                       Echar_length= V2_str.length();                                   
  349.                      if (oldstringlength != Echar_length)
  350.                          {
  351.                            oldstringlength= Echar_length;
  352.                            LCDPrintString(1,33,"       ");//clean some digit                           
  353.                          }
  354.                       delay(300);   
  355.                               
  356.            break;   
  357.    }  
  358.   }
  359. }

  360. //=============================================================
  361. //             Send Data or Command to LCD
  362. //=============================================================
  363. void LCDSendByte(char d,char RS)
  364. {
  365.   char dH,dL,temp;
  366.   //Keep Data on upper nybble
  367.   dH = d & 0xF0;         //Get MSB
  368.   dL = d & 0x0F;
  369.   dL = d << 4;           //Get LSB
  370. //Send MSB with E=clock  
  371.   temp=0;
  372.   temp=dH | RS | 0x02;  //MSB With RS+E bit
  373.   ShiftData(temp);
  374. //Send MSB with E=0
  375.   temp=0;
  376.   temp=dH | RS;  //MSB With RS bit
  377.   ShiftData(temp);
  378. //Send LSB with E=clock
  379.   temp=0;
  380.   temp=dL | RS | 0x02;  //MSB With RS+E bit
  381.   ShiftData(temp);
  382. //Send LSB with E=0
  383.   temp=0;
  384.   temp=dL | RS;  //MSB With RS bit
  385.   ShiftData(temp);  
  386. }
  387. //=============================================
  388. void ShiftData(char temp)
  389. {
  390.   int i;
  391.   for(i=0;i<8;i++)      
  392.   {
  393.     if((temp & 0x80)==0x80)    //Send 1-bit to shift register
  394.     {digitalWrite(Data,HIGH);}
  395.     else
  396.     {digitalWrite(Data,LOW);}         
  397.     digitalWrite(Clock,LOW);
  398.     digitalWrite(Clock,HIGH);
  399.     temp=temp<<1;
  400.   }
  401.   //Latch the data
  402.   digitalWrite(Latch,LOW);
  403.   delay(1);
  404.   digitalWrite(Latch,HIGH);        
  405. }
  406. //=================================================================
  407. //           LCD Display Initialization Function
  408. //=================================================================
  409. void LCDinit()
  410. {
  411.   int count;
  412.   char t[]={0x43,0x03,0x03,0x02,0x28,0x01,0x0C,0x06,0x02,0x02};   
  413.       for (count = 0; count <= 9; count++)
  414.       {
  415.         LCDSendByte(t[count],0);    //Command RS=0
  416.       }
  417. }
  418. //=================================================================
  419. //        Display Line on LCD at desired location Function
  420. //=================================================================
  421. void LCDPrint(char Line,char string[40])//--------------------------------------
  422. {
  423. int len,count;
  424. if(Line==0) {
  425.    LCDSendByte(0x80,0);    //Command RS=0 Move Cursor to Home   
  426. }
  427. else {
  428.    LCDSendByte(0xC0,0);    //Command RS=0 Move Cursor to Second Line LCDSendByte(0xC0,0);
  429. }
  430.         len = strlen(string);
  431.     for (count=0;count<len;count++)
  432.   {
  433.      LCDSendByte(string[count],1);  //Data RS=1
  434.   }
  435. }
  436. //=================================================================
  437. void LCDclean(void)
  438. {
  439.   LCDSendByte(0x01,0);
  440. }
  441. void LCDCurserMove(int y,int x)
  442. {
  443. // LCDSendByte((a*4+16),0);//a=1 shift right
  444. if (y == 0)
  445.        {   
  446.        LCDSendByte(0x80 + x,0);
  447.        }   
  448. else
  449.        {   
  450.        LCDSendByte(0xC0 + x,0);   
  451.        }      
  452. LCDSendByte(0x0b,0);   
  453. }

  454. void LCDPrintString(int x,int y, char string[])
  455. {  
  456.   int count, len;  
  457. // summ = x;
  458. if (x == 0)
  459.        {  
  460.          LCDSendByte(0x80+y ,0);
  461.        }
  462. else
  463.        {
  464.        LCDSendByte(0xC0+y,0);  
  465.        }      
  466.      len = strlen(string);
  467.     for (count=0;count<len;count++)
  468.   {
  469.      LCDSendByte(string[count],1);  //Data RS=1
  470.   }
  471. }


  472. void LCDWriteChar(int x,int y,char Data)
  473. {

  474. if (x == 0)
  475.        {   
  476.        LCDSendByte(0x80 + y,0);
  477.        }   
  478. else
  479.        {   
  480.        LCDSendByte(0xC0 + y,0);   
  481.        }      
  482. LCDSendByte(Data,1);   
  483. }

  484. void LCDhome(void)
  485. {
  486.   LCDSendByte(0x02,0);
  487. }

  488. void LCDDisp(void)
  489. {
  490.    LCDSendByte(0x0f,0);
  491. }

  492.    void PinA(){
  493.   cli(); //stop interrupts happening before we read pin values
  494.   reading = PIND & 0xC;
  495.   if(reading == B00001100 && aFlag) {
  496.     encoderPos --;
  497.     bFlag = 0;
  498.     aFlag = 0;
  499.   }
  500.   else if (reading == B00000100) bFlag = 1;
  501.   sei(); //restart interrupts
  502. }
  503. void PinB(){
  504.   cli(); //stop interrupts happening before we read pin values
  505.   reading = PIND & 0xC;
  506.   if (reading == B00001100 && bFlag) {
  507.     encoderPos ++;
  508.     bFlag = 0;
  509.     aFlag = 0;
  510.   }
  511.   else if (reading == B00001000) aFlag = 1;
  512.   sei(); //restart interrupts
  513. }

  514. void GetEncoder()//encode Position data from interrupt real time
  515. {   
  516.    if(oldEncPos != encoderPos)
  517.    {
  518.     Serial.println(encoderPos);
  519.     oldEncPos = encoderPos;
  520.     encoder_change_flag =true;
  521.   }
  522.    Echar = encoderPos;
  523. }
  524. //-------------------------------AD7840--------------------------------------
  525. void AD7840driv(int ADPin,int temp)
  526. {

  527.   Serial.print(" Analog out Data = ");
  528.   Serial.println(temp);
  529. // digitalWrite(SDataPin,LOW);
  530.   digitalWrite(ADPin,LOW);
  531.   digitalWrite(SyncPin,LOW);
  532.   delay(1);
  533.   int i;
  534.   for(i=0;i<16;i++)
  535.   {
  536.      digitalWrite(ClockPin,HIGH);
  537.    //  delay(1);
  538.     if((temp & 0x8000)==0x8000)   
  539.      // {digitalWrite(SDataPin,HIGH);}
  540.      {digitalWrite(ADPin,HIGH);}
  541.       else
  542.       // {digitalWrite(SDataPin,LOW);}  
  543.      {digitalWrite(ADPin,LOW);}     
  544.      digitalWrite(ClockPin,LOW);
  545.      temp=temp<<1;
  546.   }
  547.   //  digitalWrite(SDataPin,LOW);
  548.     digitalWrite(ADPin,LOW);
  549.     digitalWrite(SyncPin,HIGH);
  550.    delay(1);
  551.        digitalWrite(ClockPin,HIGH);
  552.    }

  553.   int Read_Encoder_SW(void)
  554.   {
  555.     if(!digitalRead(EncoderSW))//
  556.    {
  557.     delay(50);//50
  558.     if(!digitalRead(EncoderSW))
  559.     {   
  560.      return 1;
  561.      flagread =true;
  562.     }
  563.    }
  564. // Serial.println("return ");//important this have delay time
  565.   delay(150);//150
  566.   }
複製代碼

補充內容 (2019-3-11 12:10 AM):
已經解決!!
發表於 2019-3-10 17:06:00 | 顯示全部樓層
目前你的線路裡的U3的CS/Serial為空接.
 樓主| 發表於 2019-3-10 19:22:45 | 顯示全部樓層
scottwang 發表於 2019-3-10 05:06 PM
目前你的線路裡的U3的CS/Serial為空接.

SCOTTWANG大:
    線路漏畫到,實際上有接上!!
發表於 2019-3-10 21:40:44 | 顯示全部樓層
本文章最後由 jjww163 於 2019-3-10 10:02 PM 編輯

根據線路圖,clock 與 sync 是同時接到四個 DAC。
所以說在寫入資料到某一個 DAC 的時候,其他三個 DAC 也會有資料一起寫入,
不過你在 AD7840driv() 裡面卻只有設定其中一個 data, 漏了其他三個。

建議將原來 AD7840driv() 分成兩個,一個用來設定資料,儲存在 global variables 裡面準備輸出,
一個用來輸出,要 toggle clock 之前,要將四個 data pin 都設定好。
For example,


  1. int adcData[4] = {0,0,0,0};

  2. AD7840DataSet( pinNum, data) {
  3.    adcData[...] = data;
  4. }
  5. AD7840DataOut(void) {
  6.   for (...) {
  7.     if (adcData[0]...)
  8.       digitalWrite(SDataPin1, ...);
  9.     if (adcData[1]...)
  10.       digitalWrite(SDataPin2, ...);
  11.     if (adcData[2]...)
  12.       digitalWrite(SDataPin3, ...);
  13.     if (adcData[3]...)
  14.       digitalWrite(SDataPin4, ...);
  15.     // toggle clock
  16.     ...
  17.   }
  18. }
複製代碼

評分

1

查看全部評分

發表於 2019-3-10 22:49:31 | 顯示全部樓層
本文章最後由 jojoling 於 2019-3-10 10:54 PM 編輯

你的電路4顆 dac是同時寫入的,所以需要改成一次寫入4顆。

  1. AD7840driv( uint8_t nSelect,uint16_t Volt_value100) {
  2.   static uint16_t dac_out[4];

  3.   dac_out[nSelect] = Volt_value100;
  4.   for (i=0;i<16;i++) {
  5.     // assign AD pin 0 by dac_out[0]
  6.     // assign AD pin 1 by dac_out[1]
  7.     // assign AD pin 2 by dac_out[2]
  8.     // assign AD pin 3 by dac_out[3]
  9.   
  10.     // clock pin high
  11.     // delay()
  12.     // clock pin low  
  13.   }
  14. }
複製代碼
 樓主| 發表於 2019-3-10 23:35:34 | 顯示全部樓層
jjww163 發表於 2019-3-10 09:40 PM
根據線路圖,clock 與 sync 是同時接到四個 DAC。
所以說在寫入資料到某一個 DAC 的時候,其他三個 DAC 也 ...

const int SyncPin=9;//AD7840
const int ClockPin=10;//AD7840
const int SDataPin=11;//AD7840
const int SDataPin2=12;//AD78402
兩組 data 的獨立接腳,我的方式是獨立送出,所以沒有送出的接腳就變成low 而導致輸出變為0.
感謝提出問題癥結

評分

1

查看全部評分

 樓主| 發表於 2019-3-10 23:40:28 | 顯示全部樓層
jojoling 發表於 2019-3-10 10:49 PM
你的電路4顆 dac是同時寫入的,所以需要改成一次寫入4顆。

感謝 JOJOLING(舅)大的提醒,我來想想該如何改程式!!
 樓主| 發表於 2019-3-11 00:09:19 | 顯示全部樓層
感謝大家的協助,已經完成了!! 程式如下:

  1. //MERGE ENCODER AND LCM DISPLAY
  2. static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
  3. static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
  4. volatile byte aFlag = 0;
  5. volatile byte bFlag = 0;
  6. volatile long encoderPos = 0;
  7. volatile long oldEncPos = 0;
  8. volatile byte reading = 0;
  9. const int EncoderSW = 4;//Enter SW
  10. //-------------upper is encoder ------------------------------

  11. //Define 74HC595 Connections with arduio
  12. const int Latch=5; //LCM
  13. const int Data=6;  //LCM
  14. const int Clock=7; //LCM
  15. const int OEnPin=8;//output enable OPA
  16. const int SyncPin=9;//AD7840
  17. const int ClockPin=10;//AD7840
  18. const int SDataPin=11;//AD7840
  19. const int SDataPin2=12;//AD78402

  20. const byte Volt_in =A0;
  21. const byte Current_in = A3;

  22. // const int Led=13;//Led on off
  23. void LCDinit(void);
  24. void LCDSendByte(char d,char RS);
  25. void LCDPrint(char Line,char string[40]);//------------------------------------
  26. String msg;
  27. boolean flagread = false;//rs232 updata
  28. String msgdisplay;
  29. char msgbuf[20];//rs232 read buffer
  30. char Echar_Array[40];//char array 15 character ------------------------------
  31. char msgdisplay_Array[40];//display setting data  --------------------------------
  32. char V2_Array[5];
  33. int Echar_length;
  34. int oldstringlength;
  35. String Echar_str;
  36. long Echar;
  37. long SetData;//form rs232 PC
  38. boolean flag1st = true;
  39. int SWcount;
  40. int Volt_value =0;
  41. int Curr_value =0;
  42. int Volt_value2 =0;
  43. int Curr_value2 =0;
  44. int old_Volt_value;
  45. int old_Curr_value;
  46. boolean encoder_change_flag = false;
  47. boolean Encoder_flag = false;
  48. int Menu_curs;
  49. int Old_Menu_curs;
  50. static int display_time_count =0;
  51. int Level0 =0;
  52. boolean init_flag = false;
  53. boolean Display_flag;
  54. int old_value;
  55. int Volt_oldstringlength;
  56. void setup() {
  57.   pinMode(pinA, INPUT_PULLUP); // set pinA as an input _PULLUP
  58.   pinMode(pinB, INPUT_PULLUP); // set pinB as an input _PULLUP
  59.   attachInterrupt(0,PinA,RISING); // set an interrupt on PinA
  60.   attachInterrupt(1,PinB,RISING); // set an interrupt on PinB
  61.   Serial.begin(38400); // start the serial monitor link
  62. //--------------------------------   encoder --------------------------
  63.    pinMode(EncoderSW, INPUT_PULLUP);         
  64. //------------------------------^^^-- encoder --^^^----------------------------------
  65. //-----------------vvv-LCM -vvv-----------------
  66.   pinMode(Data, OUTPUT);
  67.   pinMode(Clock, OUTPUT);
  68.   pinMode(Latch, OUTPUT);  
  69. //----------AD7840 ------------------
  70. pinMode(ClockPin,OUTPUT);//AD7840
  71. pinMode(SDataPin,OUTPUT);//AD7840
  72.   pinMode(SDataPin2,OUTPUT);//AD7840
  73. pinMode(SyncPin,OUTPUT);//AD7840
  74. pinMode(OEnPin,OUTPUT);//OPA Vss
  75. // pinMode(Volt_in,INPUT);//analog input
  76. // pinMode(Current_in,INPUT);//analog input  
  77. //------------output initial ------------
  78. digitalWrite(OEnPin,HIGH);
  79. digitalWrite(SyncPin,HIGH);
  80.   digitalWrite(ClockPin,HIGH);
  81.   LCDinit();  //initalize LCD in 4-bit mode
  82.   LCDPrint(0,"> Set Voltage Hello");
  83.   LCDPrint(1,"> Set Current start");
  84.   LCDPrintString(0,20,"> Voltage Out  2019");
  85.   LCDPrintString(1,20,"> Current Out Mar-10");
  86. }

  87. void loop() {
  88.          while (!digitalRead(EncoderSW))  
  89.   while(1)
  90.   {
  91.      digitalWrite(OEnPin,LOW);
  92.     GetEncoder();
  93.      encoderPos = 0;
  94.     Menu_curs += Echar;
  95.    if(Old_Menu_curs != Menu_curs)
  96.    {
  97.     Old_Menu_curs = Menu_curs;
  98.     Display_flag = true;
  99.    }  
  100.    
  101.     if((Menu_curs >4) ||(Menu_curs <0) )
  102.     {
  103.       Menu_curs =0;
  104.       init_flag = true;
  105.     }
  106.    
  107.   switch (Menu_curs)
  108.   {
  109.     case 0:
  110.              if(Display_flag)
  111.              {
  112.                LCDPrintString(0,0, "^ Set Voltage ");
  113.                LCDWriteChar(0,0,'^');
  114.                LCDWriteChar(1,0,'>');
  115.                LCDWriteChar(0,20,'>');
  116.                LCDWriteChar(1,20,'>');
  117.                Display_flag = false;
  118.              }
  119.             Level0 = Read_Encoder_SW();//Read encoder sw to Level0
  120.             if(Level0 ==1)
  121.             {
  122.               boolean Level1=true;
  123.               LCDWriteChar(0,1,'>');
  124.               while(Level1)
  125.                 {
  126.                  GetEncoder();
  127.                  Volt_value +=Echar;
  128.                  encoderPos = 0;
  129.                  if(Volt_value != old_value)
  130.                    {
  131.                     old_value = Volt_value;
  132.                     boolean UpdateLCD_flag = true;                  
  133.                     if(UpdateLCD_flag)
  134.                     {
  135.                       String V2_str = String(Volt_value);
  136.                       V2_str.toCharArray(V2_Array,5);
  137.                       LCDPrintString(0,14,V2_Array);
  138.                       int Echar_length= V2_str.length();                     
  139.                      if (oldstringlength != Echar_length)
  140.                          {
  141.                            oldstringlength= Echar_length;
  142.                            LCDPrintString(0,13,"      ");//clean some digit  
  143.                            LCDPrintString(0,14,V2_Array);//------------------                           
  144.                          }
  145.                            Echar=0;
  146.                            int Volt_value100 = Volt_value *231;
  147.                            int Curr_value100 = Curr_value *232;
  148.                            AD7840driv(SDataPin,Volt_value100,SDataPin2,Curr_value100);
  149.                            UpdateLCD_flag = false;
  150.                      }              
  151.                     }
  152.                      int Level0level1= Read_Encoder_SW();
  153.                      if (Level0level1 ==1)
  154.                         {
  155.                           Level0 =0;
  156.                           Level1 = false;
  157.                           LCDWriteChar(0,1,' ');
  158.                         }   
  159.                    }
  160.                 }            
  161.              break;
  162.    
  163.     case 1:
  164.              if(Display_flag)
  165.              {
  166.                LCDPrintString(1,0, "^ Set Current ");
  167.                LCDWriteChar(0,0,'>');
  168.                LCDWriteChar(1,0,'^');
  169.                LCDWriteChar(0,20,'>');
  170.                LCDWriteChar(1,20,'>');
  171.                Display_flag = false;
  172.              }
  173.             Level0 = Read_Encoder_SW();//Read encoder sw to Level0
  174.             if(Level0 ==1)
  175.             {
  176.               boolean Level1=true;
  177.               LCDWriteChar(1,1,'>');
  178.               while(Level1)
  179.                 {
  180.                  GetEncoder();
  181.                  Curr_value +=Echar;
  182.                  encoderPos = 0;
  183.                  if(Curr_value != old_value)
  184.                    {
  185.                     old_value = Curr_value;
  186.                     boolean UpdateLCD_flag = true;
  187.                    if(UpdateLCD_flag)
  188.                      {
  189.                       String V2_str = String(Curr_value);
  190.                       V2_str.toCharArray(V2_Array,5);
  191.                       LCDPrintString(1,14,V2_Array);
  192.                       int Echar_length= V2_str.length();                     
  193.                      if (oldstringlength != Echar_length)
  194.                          {
  195.                            oldstringlength= Echar_length;
  196.                            LCDPrintString(1,13,"      ");//clean some digit  
  197.                            LCDPrintString(1,14,V2_Array);//------------------                           
  198.                          }
  199.                            Echar=0;
  200.                            int Volt_value100 = Volt_value *231;
  201.                            int Curr_value100 = Curr_value *232;
  202.                            AD7840driv(SDataPin,Volt_value100,SDataPin2,Curr_value100);
  203.                            UpdateLCD_flag = false;
  204.                      }              
  205.                     }
  206.                       int Level0level1= Read_Encoder_SW();
  207.                      if (Level0level1 ==1)
  208.                         {
  209.                           Level0 =0;
  210.                           Level1 = false;
  211.                           LCDWriteChar(1,1,' ');
  212.                         }   
  213.                    }
  214.                 }
  215.              break;
  216.         case 2:
  217.             if(Display_flag)
  218.              {
  219.                LCDPrintString(0,20, "^ Voltage Out");
  220.                LCDWriteChar(0,0,'>');
  221.                LCDWriteChar(1,0,'>');
  222.                LCDWriteChar(0,20,'^');
  223.                LCDWriteChar(1,20,'>');
  224.                Display_flag = false;
  225.              }
  226.             Level0 = Read_Encoder_SW();//Read encoder sw to Level0
  227.             if(Level0 ==1)
  228.             {
  229.               boolean Level1=true;
  230.               LCDWriteChar(0,21,'>');
  231.               while(Level1)
  232.                 {
  233.                 // GetEncoder();
  234.                  Volt_value2 =analogRead(Volt_in);
  235.                //  encoderPos = 0;
  236.                  if(Volt_value2 != old_Volt_value)
  237.                    {
  238.                     old_Volt_value = Volt_value2;
  239.                     boolean UpdateLCD_flag = true;                  
  240.                     if(UpdateLCD_flag)
  241.                     {
  242.                       String V2_str = String(Volt_value2);
  243.                       V2_str.toCharArray(V2_Array,5);
  244.                       LCDPrintString(0,34,V2_Array);
  245.                       int Echar_length= V2_str.length();                     
  246.                      if (oldstringlength != Echar_length)
  247.                          {
  248.                            oldstringlength= Echar_length;
  249.                            LCDPrintString(0,33,"       ");//clean some digit                           
  250.                          }
  251.                            Echar=0;
  252.                          //  AD7840driv(SDataPin,Volt_value2);
  253.                            UpdateLCD_flag = false;
  254.                      }              
  255.                     }
  256.                       int Level0level1= Read_Encoder_SW();
  257.                      if (Level0level1 ==1)
  258.                         {
  259.                           Level0 =0;
  260.                           Level1 = false;
  261.                           LCDWriteChar(0,21,' ');
  262.                         }   
  263.                    }
  264.                 }              
  265.              break;
  266.         case 3:
  267.             if(Display_flag)
  268.              {
  269.                LCDPrintString(1,20, "^ Current Out");
  270.                LCDWriteChar(0,0,'>');
  271.                LCDWriteChar(1,0,'>');
  272.                LCDWriteChar(0,20,'>');
  273.                LCDWriteChar(1,20,'^');
  274.                Display_flag = false;
  275.              }
  276.             Level0 = Read_Encoder_SW();//Read encoder sw to Level0
  277.             if(Level0 ==1)
  278.             {
  279.               boolean Level1=true;
  280.               LCDWriteChar(1,21,'>');
  281.               while(Level1)
  282.                 {
  283.                 // GetEncoder();
  284.                  Curr_value2 =analogRead(Current_in);

  285.                //  encoderPos = 0;
  286.                  if(Curr_value2 != old_Curr_value)
  287.                    {
  288.                     old_Curr_value = Curr_value2;
  289.                     boolean UpdateLCD_flag = true;                  
  290.                     if(UpdateLCD_flag)
  291.                     {
  292.                       String V2_str = String(Curr_value2);
  293.                       V2_str.toCharArray(V2_Array,5);
  294.                       LCDPrintString(1,34,V2_Array);
  295.                       int Echar_length= V2_str.length();                     
  296.                      if (oldstringlength != Echar_length)
  297.                          {
  298.                            oldstringlength= Echar_length;
  299.                            LCDPrintString(1,33,"       ");//clean some digit                           
  300.                          }
  301.                            Echar=0;
  302.                          //  AD7840driv(SDataPin,Volt_value2);
  303.                            UpdateLCD_flag = false;
  304.                      }              
  305.                     }
  306.                       int Level0level1= Read_Encoder_SW();
  307.                      if (Level0level1 ==1)
  308.                         {
  309.                           Level0 =0;
  310.                           Level1 = false;
  311.                           LCDWriteChar(1,21,' ');
  312.                         }   
  313.                    }
  314.                 }               
  315.              break;
  316.     case 4: //display screen purpose
  317.                  if(Display_flag)
  318.              {
  319.                LCDclean();
  320.                LCDPrintString(0,0, "> Set Voltage");
  321.                LCDPrintString(1,0, "> Set Current");
  322.                LCDPrintString(0,20,"> Voltage Out");
  323.                LCDPrintString(1,20,"> Current Out");
  324.                LCDWriteChar(0,0,'*');
  325.                LCDWriteChar(1,0,'*');
  326.                LCDWriteChar(0,20,'*');
  327.                LCDWriteChar(1,20,'*');
  328.                Display_flag = false;
  329.              }     
  330.                       String V2_str = String(Volt_value);
  331.                       V2_str.toCharArray(V2_Array,5);
  332.                       LCDPrintString(0,14,V2_Array);
  333.                        V2_str = String(Curr_value);
  334.                       V2_str.toCharArray(V2_Array,5);
  335.                       LCDPrintString(1,14,V2_Array);
  336.                        Volt_value2 =analogRead(Volt_in);
  337.                        V2_str = String(Volt_value2);
  338.                       V2_str.toCharArray(V2_Array,5);
  339.                       LCDPrintString(0,34,V2_Array);
  340.                       int Echar_length= V2_str.length();                  
  341.                      if (Volt_oldstringlength != Echar_length)
  342.                          {
  343.                            Volt_oldstringlength= Echar_length;                     
  344.                            LCDPrintString(0,33,"       ");//clean some digit                           
  345.                          }                     
  346.                       Curr_value2 =analogRead(Current_in);
  347.                       V2_str = String(Curr_value2);
  348.                       V2_str.toCharArray(V2_Array,5);
  349.                       LCDPrintString(1,34,V2_Array);
  350.                       Echar_length= V2_str.length();                                   
  351.                      if (oldstringlength != Echar_length)
  352.                          {
  353.                            oldstringlength= Echar_length;
  354.                            LCDPrintString(1,33,"       ");//clean some digit                           
  355.                          }
  356.                       delay(300);   
  357.                               
  358.            break;   
  359.    }  
  360.   }
  361. }

  362. //=============================================================
  363. //             Send Data or Command to LCD
  364. //=============================================================
  365. void LCDSendByte(char d,char RS)
  366. {
  367.   char dH,dL,temp;
  368.   //Keep Data on upper nybble
  369.   dH = d & 0xF0;         //Get MSB
  370.   dL = d & 0x0F;
  371.   dL = d << 4;           //Get LSB
  372. //Send MSB with E=clock  
  373.   temp=0;
  374.   temp=dH | RS | 0x02;  //MSB With RS+E bit
  375.   ShiftData(temp);
  376. //Send MSB with E=0
  377.   temp=0;
  378.   temp=dH | RS;  //MSB With RS bit
  379.   ShiftData(temp);
  380. //Send LSB with E=clock
  381.   temp=0;
  382.   temp=dL | RS | 0x02;  //MSB With RS+E bit
  383.   ShiftData(temp);
  384. //Send LSB with E=0
  385.   temp=0;
  386.   temp=dL | RS;  //MSB With RS bit
  387.   ShiftData(temp);  
  388. }
  389. //=============================================
  390. void ShiftData(char temp)
  391. {
  392.   int i;
  393.   for(i=0;i<8;i++)      
  394.   {
  395.     if((temp & 0x80)==0x80)    //Send 1-bit to shift register
  396.     {digitalWrite(Data,HIGH);}
  397.     else
  398.     {digitalWrite(Data,LOW);}         
  399.     digitalWrite(Clock,LOW);
  400.     digitalWrite(Clock,HIGH);
  401.     temp=temp<<1;
  402.   }
  403.   //Latch the data
  404.   digitalWrite(Latch,LOW);
  405.   delay(1);
  406.   digitalWrite(Latch,HIGH);        
  407. }
  408. //=================================================================
  409. //           LCD Display Initialization Function
  410. //=================================================================
  411. void LCDinit()
  412. {
  413.   int count;
  414.   char t[]={0x43,0x03,0x03,0x02,0x28,0x01,0x0C,0x06,0x02,0x02};   
  415.       for (count = 0; count <= 9; count++)
  416.       {
  417.         LCDSendByte(t[count],0);    //Command RS=0
  418.       }
  419. }
  420. //=================================================================
  421. //        Display Line on LCD at desired location Function
  422. //=================================================================
  423. void LCDPrint(char Line,char string[40])//--------------------------------------
  424. {
  425. int len,count;
  426. if(Line==0) {
  427.    LCDSendByte(0x80,0);    //Command RS=0 Move Cursor to Home   
  428. }
  429. else {
  430.    LCDSendByte(0xC0,0);    //Command RS=0 Move Cursor to Second Line LCDSendByte(0xC0,0);
  431. }
  432.         len = strlen(string);
  433.     for (count=0;count<len;count++)
  434.   {
  435.      LCDSendByte(string[count],1);  //Data RS=1
  436.   }
  437. }
  438. //=================================================================
  439. void LCDclean(void)
  440. {
  441.   LCDSendByte(0x01,0);
  442. }
  443. void LCDCurserMove(int y,int x)
  444. {
  445. // LCDSendByte((a*4+16),0);//a=1 shift right
  446. if (y == 0)
  447.        {   
  448.        LCDSendByte(0x80 + x,0);
  449.        }   
  450. else
  451.        {   
  452.        LCDSendByte(0xC0 + x,0);   
  453.        }      
  454. LCDSendByte(0x0b,0);   
  455. }

  456. void LCDPrintString(int x,int y, char string[])
  457. {  
  458.   int count, len;  
  459. // summ = x;
  460. if (x == 0)
  461.        {  
  462.          LCDSendByte(0x80+y ,0);
  463.        }
  464. else
  465.        {
  466.        LCDSendByte(0xC0+y,0);  
  467.        }      
  468.      len = strlen(string);
  469.     for (count=0;count<len;count++)
  470.   {
  471.      LCDSendByte(string[count],1);  //Data RS=1
  472.   }
  473. }


  474. void LCDWriteChar(int x,int y,char Data)
  475. {

  476. if (x == 0)
  477.        {   
  478.        LCDSendByte(0x80 + y,0);
  479.        }   
  480. else
  481.        {   
  482.        LCDSendByte(0xC0 + y,0);   
  483.        }      
  484. LCDSendByte(Data,1);   
  485. }

  486. void LCDhome(void)
  487. {
  488.   LCDSendByte(0x02,0);
  489. }

  490. void LCDDisp(void)
  491. {
  492.    LCDSendByte(0x0f,0);
  493. }

  494.    void PinA(){
  495.   cli(); //stop interrupts happening before we read pin values
  496.   reading = PIND & 0xC;
  497.   if(reading == B00001100 && aFlag) {
  498.     encoderPos --;
  499.     bFlag = 0;
  500.     aFlag = 0;
  501.   }
  502.   else if (reading == B00000100) bFlag = 1;
  503.   sei(); //restart interrupts
  504. }
  505. void PinB(){
  506.   cli(); //stop interrupts happening before we read pin values
  507.   reading = PIND & 0xC;
  508.   if (reading == B00001100 && bFlag) {
  509.     encoderPos ++;
  510.     bFlag = 0;
  511.     aFlag = 0;
  512.   }
  513.   else if (reading == B00001000) aFlag = 1;
  514.   sei(); //restart interrupts
  515. }

  516. void GetEncoder()//encode Position data from interrupt real time
  517. {   
  518.    if(oldEncPos != encoderPos)
  519.    {
  520.     Serial.println(encoderPos);
  521.     oldEncPos = encoderPos;
  522.     encoder_change_flag =true;
  523.   }
  524.    Echar = encoderPos;
  525. }
  526. //-------------------------------AD7840--------------------------------------
  527. void AD7840driv(int ADPin0,int tempV,int ADPin1,int tempC)//2019 03 10 V3
  528. {


  529. // digitalWrite(SDataPin,LOW);
  530.   digitalWrite(ADPin0,LOW);// 2 digital pin LOW
  531.   digitalWrite(ADPin1,LOW);
  532.   digitalWrite(SyncPin,LOW);
  533.   delay(1);
  534.   int i;
  535.   for(i=0;i<16;i++)
  536.   {
  537.      digitalWrite(ClockPin,HIGH);
  538.    //  delay(1);
  539.     if((tempV & 0x8000)==0x8000)  
  540.      {digitalWrite(ADPin0,HIGH);}
  541.       else
  542.      {digitalWrite(ADPin0,LOW);}  
  543.     if((tempC & 0x8000)==0x8000)  
  544.      {digitalWrite(ADPin1,HIGH);}
  545.       else
  546.      {digitalWrite(ADPin1,LOW);}      
  547.    
  548.      digitalWrite(ClockPin,LOW);
  549.      tempV=tempV<<1;
  550.      tempC=tempC<<1;     
  551.   }
  552.   //  digitalWrite(SDataPin,LOW);
  553.     digitalWrite(ADPin0,LOW);
  554.     digitalWrite(ADPin1,LOW);
  555.    
  556.     digitalWrite(SyncPin,HIGH);
  557.    delay(1);
  558.        digitalWrite(ClockPin,HIGH);
  559.    }

  560.   int Read_Encoder_SW(void)
  561.   {
  562.     if(!digitalRead(EncoderSW))//
  563.    {
  564.     delay(50);//50
  565.     if(!digitalRead(EncoderSW))
  566.     {   
  567.      return 1;
  568.      flagread =true;
  569.     }
  570.    }
  571. // Serial.println("return ");//important this have delay time
  572.   delay(150);//150
  573.   }
複製代碼

評分

6

查看全部評分

您需要登錄後才可以回帖 登錄 | 立即註冊

本版積分規則

關閉

站長小叮嚀上一條 /1 下一條

禁閉室|手機版|連繫我們|痞酷網電子技術論壇

GMT+8, 2024-4-23 05:32 PM , Processed in 0.068697 second(s), 21 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.