Thông báo

Collapse
No announcement yet.

[STM32F10x] - Các vấn đề liên quan đến chuyển đổi ADC.

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • [STM32F10x] - Các vấn đề liên quan đến chuyển đổi ADC.

    Mình đang tìm hiểu cách sử dụng modul ADC ở chế độ đa kênh của STM32F10x.
    Với chế độ đơn kênh thì giá trị ADC được lấy bằng câu lệnh :
    Code:
    uint16_t adc;
    adc=ADC_GetConversionValue(ADC1);
    Ví dụ đang sử dụng ADC1.

    Tuy nhiên sang chế độ chuyển đổi đa kênh mình đã thấy giá trị của ADC1 thay đổi liên tục khi quét qua các kênh nhưng không làm thế nào lấy được giá trị của từng kênh vào trong chương trình. Mình đã đọc qua thư viện của nó ( bộ thư viện chuẩn CMSIS ) nhưng không tìm thấy hàm phục vụ việc ấy. Nhờ các bác đi trước cho xin cao kiến
    (Mình không dùng DMA - tại là chưa hiểu nó )

  • #2
    chú ý khi đọc ADC ở các kênh khác nhau thì bác phải check ADC_FLAG_EOC trước đã. Và việc quét đa kênh thì có thể sử dụng phương pháp injected

    Comment


    • #3
      Nguyên văn bởi chumanh Xem bài viết
      chú ý khi đọc ADC ở các kênh khác nhau thì bác phải check ADC_FLAG_EOC trước đã. Và việc quét đa kênh thì có thể sử dụng phương pháp injected
      Theo mình hiểu thì ADC_FLAG_EOC là cờ báo hiệu trạng thái của bộ chuyển đổi. Nhưng vấn đề mình gặp ở đây là bộ chuyển đổi liên tục quét qua các kênh đã chọn và tự động chuyển đổi độc lập và làm cách nào để biết nó đang đọc kênh nào để lấy giá trị tương ứng vào chương trình.
      Injected thì mới đọc qua cũng chưa hiểu lắm. Gà mờ nhờ bác chỉ giáo thêm
      Dưới là đoạn code mình viết, nhờ bác xem giúp xem sai chỗ nào
      Code:
      #include <stm32f10x.h>
      
      
      /* Variables */
      uint16_t ADC_Converted[2];
      
      int main(void)
      {
      	/* Init Type Define */
      	GPIO_InitTypeDef GPIO_InitStructure;
      	ADC_InitTypeDef ADC_InitStructure;
      
      	/*RCC Configuration */
      	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
      	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
      	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
      	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
      	
      	/*GPIO A Configuration */
      	GPIO_DeInit(GPIOA);
      	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
      	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
      	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
      	GPIO_Init(GPIOA, &GPIO_InitStructure);
      
      	/* GPIO B Configuration */
      	GPIO_DeInit(GPIOB);
      	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
      	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
      	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
      	GPIO_Init(GPIOB, &GPIO_InitStructure);
      
      	/* GPIO C Configuration */
      	GPIO_DeInit(GPIOC);
      	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
      	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
      	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
      	GPIO_Init(GPIOC, &GPIO_InitStructure);
      
      	/* ADC1 Configuration */
      	ADC_DeInit(ADC1);
      	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
      	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
      	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
      	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
      	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      	ADC_InitStructure.ADC_NbrOfChannel = 2;
      	ADC_Init(ADC1, &ADC_InitStructure);
      
      	/* ADC1 Regular Channel Configuration */
      	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_1Cycles5);
      	ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_1Cycles5);
      
      	/* ADC1 Start */
      	ADC_Cmd(ADC1,ENABLE);
      
      	/* Enable Vrefint channel enable temperature sensor for ADC module */
      	ADC_TempSensorVrefintCmd(ENABLE);
      
      	/* Enable ADC1 reset calibaration register */   
              ADC_ResetCalibration(ADC1);
      
              /* Check the end of ADC1 reset calibration register */
              while(ADC_GetResetCalibrationStatus(ADC1));
      
              /* Start ADC1 calibaration */
              ADC_StartCalibration(ADC1);
      
              /* Check the end of ADC1 calibration */
              while(ADC_GetCalibrationStatus(ADC1));  
      
      	/* Start ADC1 Software Conversion */ 
      	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
      
      	/* Start Main From */
      	while(1)
      	{
      		ADC_Converted[0]=ADC_GetInjectedConversionValue(ADC1,ADC_Channel_1);
      		ADC_Converted[1]=ADC_GetInjectedConversionValue(ADC1,ADC_Channel_2);
      
      		GPIO_Write(GPIOB,ADC_Converted[0]);
      		GPIO_Write(GPIOC,ADC_Converted[1]);
      	}
      
      }
      Last edited by duong_act; 05-09-2012, 18:39.

      Comment


      • #4
        Up !!!
        Diễn đàn ta không bác nào chơi con này à. Vào giúp mình một tay với

        Comment


        • #5
          mình dùng CM0 của thằng NXP. nghe nói thằng này có nhiều sample code mẫu lắm mà. bạn vào trang chủ của nó download về xem thử xem.
          Never forget who you are!

          Comment


          • #6
            Nguyên văn bởi duong_act Xem bài viết
            Up !!!
            Diễn đàn ta không bác nào chơi con này à. Vào giúp mình một tay với
            Dùng mikroC chỉ có ADC1 Init ... với ADC_Read ...

            --- ARM cũng đơn giản như mấy con 89 , PIC ... piếc gì đó thôi !
            Module RF chuyên dụng điều khiển, truyền dữ liệu, thiết kế đề tài, dự án điện tử - chuyển giao công nghệ... ĐT: 0904964977 - email: dientuqueduong@yahoo.com

            Comment


            • #7
              Bác có thể dùng DMA, nó cũng đơn giản thôi, chỉ là bộ điều khiển truy cập trực tiếp dữ liệu RAM mà không thông qua lõi CPU của con MCU ARM. Bản thân bộ ADC cũng được trang bị bộ điều khiển DMA do đó có thể sử dụng DMA để lấy trực tiếp giá trị ADC đã chuyển đổi được lưu trữ trong RAM do vậy cho tốc độ cực cao và giảm tải CPU.

              From ST: "DMA is a major feature and its use is recommended when possible to avoid the loss of
              samples and release the CPU load.
              "

              Còn về cơ chế injected thì như code trên của bác nó không thể hoạt động được vì thiếu các thiết lập cho injected. Cụ thể thế nào thì bác xem Application note - AN3116 của ST và các ví dụ của hãng.

              Còn em có thắc mắc nhỏ, mục đích của bác là đọc nhiều kênh ADC hay mục đích của bác là "biết nó đang đọc kênh nào" ạ?

              Comment


              • #8
                Nguyên văn bởi queduong Xem bài viết
                Dùng mikroC chỉ có ADC1 Init ... với ADC_Read ...

                --- ARM cũng đơn giản như mấy con 89 , PIC ... piếc gì đó thôi !
                Nó đơn giản như PIC,AVR thì em còn hỏi làm gì hả bác

                Comment


                • #9
                  Nguyên văn bởi nhquangdt3k5 Xem bài viết
                  mình dùng CM0 của thằng NXP. nghe nói thằng này có nhiều sample code mẫu lắm mà. bạn vào trang chủ của nó download về xem thử xem.
                  Code mẫu thì mình cũng có bạn ạ. Nhưng mình muốn hiểu được nó để còn mà tùy biến cho mỗi project thôi.

                  Comment


                  • #10
                    Nguyên văn bởi itanium7000 Xem bài viết
                    Bác có thể dùng DMA, nó cũng đơn giản thôi, chỉ là bộ điều khiển truy cập trực tiếp dữ liệu RAM mà không thông qua lõi CPU của con MCU ARM. Bản thân bộ ADC cũng được trang bị bộ điều khiển DMA do đó có thể sử dụng DMA để lấy trực tiếp giá trị ADC đã chuyển đổi được lưu trữ trong RAM do vậy cho tốc độ cực cao và giảm tải CPU.

                    From ST: "DMA is a major feature and its use is recommended when possible to avoid the loss of
                    samples and release the CPU load.
                    "

                    Còn về cơ chế injected thì như code trên của bác nó không thể hoạt động được vì thiếu các thiết lập cho injected. Cụ thể thế nào thì bác xem Application note - AN3116 của ST và các ví dụ của hãng.

                    Còn em có thắc mắc nhỏ, mục đích của bác là đọc nhiều kênh ADC hay mục đích của bác là "biết nó đang đọc kênh nào" ạ?
                    Ý mình là thế này :
                    1 bộ ADC có nhiều kênh và trong chế độ multichannel thì làm thế nào để đọc được từng kênh đó.
                    Với DMA thì nó sẽ tự động load các giá trị của các kênh lên 1 mảng trên Ram và mình chỉ cần đọc giá trị trong mảng đó là lấy được giá trị của kênh ADC mình cần.
                    Cái dị đời ở đây là mình đang học và chưa thể sử dụng được DMA nên mình muốn cho nó hoạt động ở multichannel nhưng không sử dụng DMA. Có thể do mình config các thông số chưa chuẩn nên khi debug thấy ADC đã lần lượt quét qua các kênh và có chuyển đổi ( giá trị thanh ghi DR thay đổi liên tục khi quét qua các kênh) nhưng rắc rối ở đây là ADC tự động chuyển đổi và không biết căn cứ vào đâu để biết nó đang chuyển đổi giá trị của kênh nào để lấy giá trị cho chính xác. Như vậy sẽ có 2 cách để lấy :
                    - Biết nó đang chuyển đổi kênh nào để lấy giá trị tương ứng.
                    - Ra lệnh cho nó chuyển đổi kênh mình muốn.
                    Cả 2 cách này mình đều chưa biết dựa vào thanh ghi nào, câu lệnh tương ứng trong CMSIS.
                    Khi xem thư viện của nó thì mình chú ý tới cách liên quan đến Injected nhưng đã thử cấu hình lại đủ kiểu nhưng vẫn chưa chạy được
                    Nhờ các bác giúp một tay cho qua cái ải này vì còn nhiều cái phía trước
                    Code mình đã up ở trên nên bác nào rảnh rỗi chỉ giúp mình là sửa lại hay thêm bớt ở cái chỗ nào ạ

                    Comment


                    • #11
                      Nguyên văn bởi duong_act Xem bài viết
                      Nó đơn giản như PIC,AVR thì em còn hỏi làm gì hả bác
                      vì bạn chưa biết nên bạn thấy không đơn giản
                      Module RF chuyên dụng điều khiển, truyền dữ liệu, thiết kế đề tài, dự án điện tử - chuyển giao công nghệ... ĐT: 0904964977 - email: dientuqueduong@yahoo.com

                      Comment


                      • #12
                        Nguyên văn bởi queduong Xem bài viết
                        vì bạn chưa biết nên bạn thấy không đơn giản
                        Ít ra thì nó cũng phức tạp hơn của PIC,AVR bởi có nhiều chế độ, nhiều thông số cấu hình và để mà cấu hình đúng đc nếu mà tự học, sample không có thì không phải dễ ạ

                        Comment


                        • #13
                          Ôi ! Cái ... đ..ệ..t
                          Cứ tưởng có cao thủ vào giúp

                          Comment


                          • #14
                            Nguyên văn bởi duong_act Xem bài viết
                            Ôi ! Cái ... đ..ệ..t
                            Cứ tưởng có cao thủ vào giúp
                            Đã tiễn kẻ ị bậy lên đường
                            Module RF chuyên dụng điều khiển, truyền dữ liệu, thiết kế đề tài, dự án điện tử - chuyển giao công nghệ... ĐT: 0904964977 - email: dientuqueduong@yahoo.com

                            Comment


                            • #15
                              Nguyên văn bởi duong_act Xem bài viết
                              Ý mình là thế này :
                              1 bộ ADC có nhiều kênh và trong chế độ multichannel thì làm thế nào để đọc được từng kênh đó.
                              Với DMA thì nó sẽ tự động load các giá trị của các kênh lên 1 mảng trên Ram và mình chỉ cần đọc giá trị trong mảng đó là lấy được giá trị của kênh ADC mình cần.
                              Cái dị đời ở đây là mình đang học và chưa thể sử dụng được DMA nên mình muốn cho nó hoạt động ở multichannel nhưng không sử dụng DMA. Có thể do mình config các thông số chưa chuẩn nên khi debug thấy ADC đã lần lượt quét qua các kênh và có chuyển đổi ( giá trị thanh ghi DR thay đổi liên tục khi quét qua các kênh) nhưng rắc rối ở đây là ADC tự động chuyển đổi và không biết căn cứ vào đâu để biết nó đang chuyển đổi giá trị của kênh nào để lấy giá trị cho chính xác. Như vậy sẽ có 2 cách để lấy :
                              - Biết nó đang chuyển đổi kênh nào để lấy giá trị tương ứng.
                              - Ra lệnh cho nó chuyển đổi kênh mình muốn.
                              Cả 2 cách này mình đều chưa biết dựa vào thanh ghi nào, câu lệnh tương ứng trong CMSIS.
                              Khi xem thư viện của nó thì mình chú ý tới cách liên quan đến Injected nhưng đã thử cấu hình lại đủ kiểu nhưng vẫn chưa chạy được
                              Nhờ các bác giúp một tay cho qua cái ải này vì còn nhiều cái phía trước
                              Code mình đã up ở trên nên bác nào rảnh rỗi chỉ giúp mình là sửa lại hay thêm bớt ở cái chỗ nào ạ
                              ADC đa kênh có vài cách đọc, trường hợp như code mà bác đang áp dụng (scan, continue) thì để sửa cần điều chỉnh một số điểm:

                              Cần cấu hình kênh injected thay cho việc cấu hình regular:
                              Code:
                              ADC_InjectedSequencerLengthConfig(ADC1, 2);
                              ADC_InjectedChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycles5);
                              ADC_InjectedChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_7Cycles5);
                              ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_None);
                              ADC_AutoInjectedConvCmd(ADC1, ENABLE);
                              Sau khi đơi ADC1 calibration thì sử kích hoạt ADC conversion cho injected group thay vì sử dụng hàm ADC_SoftwareStartConvCmd(ADC1, ENABLE);
                              Code:
                              ADC_SoftwareStartInjectedConvCmd(ADC1, ENABLE);
                              Lấy dữ liệu converted chanel:

                              Code:
                              ADC_Converted[0] = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);
                              ADC_Converted[1] = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2);
                              Bác chú ý param thứ 2 của hàm ADC_GetInjectedConversionValue là một injected chanel từ 1 đến 4 chứ không phải là ADC_channels như bác viết ở trên. Kết quả chuyển đổi của injected chanel lưu các thanh ghi tương ứng ADC1_DRJ1, ADC1_DRJ2, ADC1_DRJ3, ADC1_DRJ4 nên cũng có thể đọc trực tiếp:
                              Code:
                              ADC_Converted[0] = (*(volatile unsigned long *) (ADC1_BASE + 0x3C));

                              Comment

                              Về tác giả

                              Collapse

                              duong_act Tìm hiểu thêm về duong_act

                              Bài viết mới nhất

                              Collapse

                              Đang tải...
                              X