爱板网论坛

查看: 540|回复: 0

[技术] 【赚周年币】技术帖Week1-Day7——LPC824 Breakout之七、ADC LCD显示

[复制链接]

24

主题

0

好友

5331

积分

状元

Rank: 6Rank: 6

  • TA的每日心情
    开心
    19 小时前
  • 签到天数: 1462 天

    连续签到: 172 天

    [LV.10]以坛为家III

    爱板会员勋章 活跃会员勋章 发帖机器勋章 在线达人勋章

    发表于 2017-1-7 22:20:47 |显示全部楼层
    本帖最后由 toofree 于 2017-1-17 23:39 编辑

            【赚周年币】技术帖Week1-Day7——LPC824 Breakout之七、ADC转换,串口同时打印,并同时在 Nokia5110 LCD上显示。
            (标题不能太长,没办法,只好在贴中写全名称)

            以上一贴最后上传压缩包做主工程模板。参见贴子最末尾的附件。
            【赚周年币】技术帖Week1-Day6——LPC824 Breakout之六、30M时钟http://www.eeboard.com/bbs/forum ... 60438&fromuid=17147
             傲游截图20170107221615.jpg

            在最新的压缩包中“LPC824_Example_Code_Bundle_Keil_r1.0(20170107).rar”,修改了nokia5110 LCD函数名称,并修正了部分Bug。

            本贴使用“Example_ADC_Seqa_Seqb”工程模板,做适当修改。完整工程如下图:
             傲游截图20170107223157.jpg


            主函数如下,红色部分为修改内容。
    1. /*
    2. ===============================================================================
    3. Name        : Example_ADC_Seqa_Seqb_main.c
    4. Author      : $(author)
    5. Version     :
    6. Copyright   : $(copyright)
    7. Description : read the readme
    8. ===============================================================================
    9. */

    10. #include "LPC8xx.h"
    11. //#include <cr_section_macros.h>
    12. #include <stdio.h>

    13. #include "lpc8xx_adc.h"
    14. #include "lpc8xx_swm.h"
    15. #include "lpc8xx_syscon.h"
    16. #include "utilities.h"

    17. #include "nokia5110.h"


    18. void setup_debug_uart(void);

    19. const char promptstring[] = "Choose a sequence to convert:\r\na for sequence a\r\nb for sequence b\r\n";

    20. volatile uint32_t seqa_buffer[12];
    21. volatile uint32_t seqb_buffer[12];
    22. volatile enum {false, true} seqa_handshake, seqb_handshake;
    23. uint32_t current_seqa_ctrl, current_seqb_ctrl;

    24. // To use software triggering, define this to '1', otherwise define it to '0' to use hardware triggering.
    25. #define SOFTWARE_TRIGGER 0
    26. //#define SOFTWARE_TRIGGER 1


    27. /*****************************************************************************
    28. *****************************************************************************/
    29. int main(void) {
    30.   unsigned char temp;
    31.   uint32_t current_clkdiv, val, temp_data, n;
    32.         uint32_t lcd_n=0;
    33.         char lcd_chr[20];

    34.   // Configure the debug uart (see Serial.c)
    35.   setup_debug_uart();

    36.   // Step 1. Power up and reset the ADC, and enable clocks to peripherals (see lpc8xx_syscon.h)
    37.   LPC_SYSCON->PDRUNCFG &= ~(ADC_PD);
    38.   LPC_SYSCON->PRESETCTRL &= (ADC_RST_N);
    39.   LPC_SYSCON->PRESETCTRL |= ~(ADC_RST_N);
    40.   LPC_SYSCON->SYSAHBCLKCTRL |= (ADC | GPIO | SWM);

    41. //  // Make P0.27 output driving '1'  connect to P0.11 externally.
    42. //  // Make P0.16 output driving '1', connect to P0.10 externally.
    43. //  LPC_GPIO_PORT->SET0  = 0x08010000;     // P0.27, P0.16 to '1'
    44. //  LPC_GPIO_PORT->DIR0 |= 0x08010000;     // P0.27, P0.16 to output
    45.         
    46.         // Make P0.15 output driving '1'  connect to P0.11 externally.
    47.   // Make P0.16 output driving '1', connect to P0.10 externally.
    48.   LPC_GPIO_PORT->SET0  = 0x00018000;     // P0.15, P0.16 to '1'
    49.   LPC_GPIO_PORT->DIR0 |= 0x00018000;     // P0.15, P0.16 to output

    50.   // Step 2. Perform a self-calibration
    51.   // Choose a CLKDIV divider value that yields about 500 KHz, we will use the SystemCoreClock variable for the calculation.
    52.   SystemCoreClockUpdate();
    53.   current_clkdiv = (SystemCoreClock / 500000) - 1;

    54.   // Start the self-calibration
    55.   // Calibration mode = true, low power mode = false, CLKDIV = appropriate for 500,000 Hz
    56.   LPC_ADC->CTRL = ( (1<<ADC_CALMODE) | (0<<ADC_LPWRMODE) | (current_clkdiv<<ADC_CLKDIV) );

    57.   // Poll the calibration mode bit until it is cleared
    58.   while (LPC_ADC->CTRL & (1<<ADC_CALMODE));

    59.   // Step 3. Configure the SWM (see utilities_lib and lpc8xx_swm.h)
    60.   // ADC1 - ADC6, ADC7, ADC9 - ADC11 pins to be ADC analog functions
    61.   // We won't use ADC0 or ADC8 because they share pins with the debug uart
    62.   LPC_SWM->PINENABLE0 &= ~(ADC_1|ADC_2|ADC_3|ADC_4|ADC_5|ADC_6|ADC_7|ADC_9|ADC_10|ADC_11); // Fixed pin analog functions enabled
    63.   LPC_SWM->PINENABLE0 |= (ADC_0|ADC_8);                                                    // Movable digital functions enabled

    64.   // Assign the ADC pin trigger functions to pins P0.10 (A seq.) and P0.11 (B seq.)
    65.   ConfigSWM(ADC_PINTRIG0, P0_10);  // ADC_PINTRIG0 will be for the A sequence
    66.   ConfigSWM(ADC_PINTRIG1, P0_11);  // ADC_PINTRIG1 will be for the B sequence

    67.   // Step 4. Configure the ADC for the appropriate analog supply voltage using the TRM register
    68.   // For a sampling rate higher than 1 Msamples/s, VDDA must be higher than 2.7 V (on the Max board it is 3.3 V)
    69.   LPC_ADC->TRM &= ~(1<<ADC_VRANGE); // '0' for high voltage

    70.   // Step 4. Choose a CLKDIV divider value
    71.   // A fully accurate conversion requires 25 ADC clocks.
    72.   // A 30 MHz system clock with CLKDIV = 0 results in 1.2 MSPS.
    73.   // We can use the SystemCoreClock variable to calculate for a desired sample rate in Hz.
    74.   #define desired_sample_rate 1200000
    75.   current_clkdiv = (SystemCoreClock / (25 * desired_sample_rate)) - 1;

    76.   // Calibration mode = false, low power mode = false, CLKDIV = appropriate for desired sample rate.
    77.   LPC_ADC->CTRL = ( (0<<ADC_CALMODE) | (0<<ADC_LPWRMODE) | (current_clkdiv<<ADC_CLKDIV) );

    78.   // Step 5. Assign some ADC channels to each sequence
    79.   // Let sequence A = channels 1, 2, 3, 4, 5, 6
    80.   // Let sequence B = channels 7, 9, 10, 11
    81. //  current_seqa_ctrl = ((1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6))<<ADC_CHANNELS;
    82. //  current_seqb_ctrl = ((1<<7)|(1<<9)|(1<<10)|(1<<11))<<ADC_CHANNELS;
    83.   current_seqa_ctrl = ((1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5))<<ADC_CHANNELS;
    84.   current_seqb_ctrl = ((1<<6)|(1<<7)|(1<<9)|(1<<10)|(1<<11))<<ADC_CHANNELS;

    85.   // Step 6. Select a trigger source for each of the sequences
    86.   // Let sequence A trigger = ADC pin trigger 0. Connected to an external pin through the switch matrix above.
    87.   // Let sequence B trigger = ADC pin trigger 1. Connected to an external pin through the switch matrix above.
    88. #if SOFTWARE_TRIGGER
    89.   current_seqa_ctrl |= LOGIC_HIGH<<ADC_TRIGGER;    // Use for software-only triggering
    90.   current_seqb_ctrl |= LOGIC_HIGH<<ADC_TRIGGER;    // Use for software-only triggering
    91. #else
    92.   current_seqa_ctrl |= ADC_PINTRIG_0<<ADC_TRIGGER; // Use for hardware triggering
    93.   current_seqb_ctrl |= ADC_PINTRIG_1<<ADC_TRIGGER; // Use for hardware triggering
    94. #endif

    95.   // Step 7. Select positive (1) or negative (0) edge for the hardware trigger
    96.   // Let sequence A be negative edge triggered
    97.   // Let sequence B be negative edge triggered
    98.   current_seqa_ctrl |= 0<<ADC_TRIGPOL;
    99.   current_seqb_ctrl |= 0<<ADC_TRIGPOL;

    100.   // Step 8. Choose (1) to bypass, or (0) not to bypass the hardware trigger synchronization
    101.   // Since our trigger sources are on-chip, system clock based, we may bypass.
    102.   current_seqa_ctrl |= 1<<ADC_SYNCBYPASS;
    103.   current_seqb_ctrl |= 1<<ADC_SYNCBYPASS;

    104.   // Step 9. Choose burst mode (1) or no burst mode (0) for each of the sequences
    105.   // Let sequences A and B use no burst mode
    106.   current_seqa_ctrl |= 0<<ADC_BURST;
    107.   current_seqb_ctrl |= 0<<ADC_BURST;

    108.   // Step 10. Choose single step (1), or not (0), for each sequence.
    109.   // Let sequences A and B use no single step
    110.   current_seqa_ctrl |= 0<<ADC_SINGLESTEP;
    111.   current_seqb_ctrl |= 0<<ADC_SINGLESTEP;

    112.   // Step 11. Choose A/B sequence priority
    113.   // Use default
    114.   current_seqa_ctrl |= 0<<ADC_LOWPRIO;

    115.   // Step 12. Choose end-of-sequence mode (1), or end-of-conversion mode (0), for each sequence
    116.   // Let sequences A and B use end-of-sequence mode
    117.   current_seqa_ctrl |= 1<<ADC_MODE;
    118.   current_seqb_ctrl |= 1<<ADC_MODE;

    119.   // Step 13. Set the low and high thresholds for both sets of threshold compare registers
    120.   // Note: This step is included for completeness, threshold crossings are not currently used in this example.
    121.   // Let both low thresholds be (1/3)*0xfff
    122.   // Let both high thresholds be (2/3)*0xfff
    123.   #define low_thresh (0xFFF / 3)
    124.   #define high_thresh ((2 * 0xFFF) / 3)
    125.   LPC_ADC->THR0_LOW = low_thresh;
    126.   LPC_ADC->THR1_LOW = low_thresh;
    127.   LPC_ADC->THR0_HIGH = high_thresh;
    128.   LPC_ADC->THR1_HIGH = high_thresh;

    129.   // Step 14. For each channel, choose which pair of threshold registers (0 or 1) conversion results should be compared against.
    130.   // Note: This step is included for completeness, threshold crossings are not currently used in this example.
    131.   // For sequence A (channels 1 - 6), compare against threshold register set 0
    132.   // For sequence B (channels 7, 9, 10, 11), compare against threshold register set 1
    133.   LPC_ADC->CHAN_THRSEL = (0<<1)|(0<<2)|(0<<3)|(0<<4)|(0<<5)|(0<<6)|(1<<7)|(1<<9)|(1<<10)|(1<<11);

    134.   // Step 15. Choose which interrupt conditions will contribute to the ADC interrupt/DMA triggers
    135.   // Only the sequence A and sequence B interrupts are enabled for this example
    136.   // SEQA_INTEN = true
    137.   // SEQB_INTEN = true
    138.   // OVR_INTEN = false
    139.   // ADCMPINTEN0 - ADCMPEN11 = false
    140.   LPC_ADC->INTEN = (1<<SEQA_INTEN)  |
    141.                    (1<<SEQB_INTEN)  |
    142.                    (0<<OVR_INTEN)   |
    143.                    (0<<ADCMPINTEN0) |
    144.                    (0<<ADCMPINTEN1) |
    145.                    (0<<ADCMPINTEN2) |
    146.                    (0<<ADCMPINTEN3) |
    147.                    (0<<ADCMPINTEN4) |
    148.                    (0<<ADCMPINTEN5) |
    149.                    (0<<ADCMPINTEN6) |
    150.                    (0<<ADCMPINTEN7) |
    151.                    (0<<ADCMPINTEN8) |
    152.                    (0<<ADCMPINTEN9) |
    153.                    (0<<ADCMPINTEN10)|
    154.                    (0<<ADCMPINTEN11);


    155.   // Write the sequence control word with enable bit set for both sequences
    156.   current_seqa_ctrl |= 1U<<ADC_SEQ_ENA;
    157.   LPC_ADC->SEQA_CTRL = current_seqa_ctrl;

    158.   current_seqb_ctrl |= 1U<<ADC_SEQ_ENA;
    159.   LPC_ADC->SEQB_CTRL = current_seqb_ctrl;

    160.   // Enable ADC interrupts in the NVIC
    161.   NVIC_EnableIRQ(ADC_SEQA_IRQn);
    162.   NVIC_EnableIRQ(ADC_SEQB_IRQn);
    163.         
    164.         Home_Init();
    165.         NOKIA5110_init();
    166.   NOKIA5110_clear_screen();
    167.         
    168.         NOKIA5110_display_1608_text (0, 0, "LPC824");
    169.         NOKIA5110_display_8x6_text (0, 2, "ADC Test !");

    170.   printf("This is a ADC test programme !\r\n");
    171.         printf("low_thresh: 0x%03X\r\n",low_thresh);
    172.         printf("high_thresh: 0x%03X\r\n",high_thresh);

    173.   while(1) {

    174.     // Prompt user to select a sequence to convert (see utilities_lib)
    175.     temp = GetConsoleCharacter((const char *)&promptstring);

    176.     // Accept 'a' only, anything else is sequence B
    177.     if (temp == 'a') {
    178.       seqa_handshake = false;

    179. #if SOFTWARE_TRIGGER
    180.       // Launch sequence A with software
    181.       current_seqa_ctrl |= 1<<ADC_START;
    182.       LPC_ADC->SEQA_CTRL = current_seqa_ctrl;
    183. #else
    184.       // Launch sequence A with hardware
    185.       LPC_GPIO_PORT->CLR0 = 0x00010000;      // Clear P0.16 to '0', creates a falling edge on ADC_PINTRIG0
    186. #endif
    187.       // Wait for return from ISR
    188.       while (!seqa_handshake);
    189.                         
    190.                         printf("\r\n");
    191.                         NOKIA5110_clear_screen();
    192.                         lcd_n = 0;
    193.       // Get the data from SRAM and print it to the terminal
    194.       for (n = 0; n < 12; n++) {
    195.         val = current_seqa_ctrl;
    196.         val = (val>>n) & 0x1;    // Shift the current channel of interest into bit 0, see if it's set
    197.         if (val) {               // If set, get this channel's data from the SRAM array
    198.           temp_data = (seqa_buffer[n]>>4) & 0x00000FFF;
    199.           printf("ADC channel %d data was %d\r\n", n, temp_data);        
    200.                                        
    201.                                         NOKIA5110_display_8x6_text (0, lcd_n, "ADC");
    202.                                         sprintf(lcd_chr,"%2d",n);
    203.                                         NOKIA5110_display_8x6_text (18, lcd_n, lcd_chr);
    204.                                         NOKIA5110_display_8x6_text (30, lcd_n, ": 0x");
    205.                                         sprintf(lcd_chr,"%4d",temp_data);
    206.                                         NOKIA5110_display_8x6_text (54, lcd_n, lcd_chr);
    207.                                         lcd_n++;
    208.         }
    209.       }
    210.     }
    211.     else if (temp == 'b'){
    212.       seqb_handshake = false;

    213. #if SOFTWARE_TRIGGER
    214.       // Launch sequence B with software
    215.       current_seqb_ctrl |= 1<<ADC_START;
    216.       LPC_ADC->SEQB_CTRL = current_seqb_ctrl;
    217. #else
    218.       // Launch sequence B with hardware
    219.       //LPC_GPIO_PORT->CLR0 = 0x08000000;      // Clear P0.27 to '0', creates a falling edge on ADC_PINTRIG1
    220.                         LPC_GPIO_PORT->CLR0 = 0x00008000;      // Clear P0.15 to '0', creates a falling edge on ADC_PINTRIG1
    221. #endif
    222.       // Wait for return from ISR
    223.       while (!seqb_handshake);
    224.                         
    225.                         printf("\r\n");
    226.                         NOKIA5110_clear_screen();
    227.                         lcd_n = 0;
    228.       // Get the data from SRAM and print it to the terminal
    229.       for (n = 0; n < 12; n++) {
    230.         val = current_seqb_ctrl;
    231.         val = (val>>n) & 0x1;    // Shift the current channel of interest into bit 0, see if it's set
    232.         if (val) {               // If set, get this channel's data from the SRAM array
    233.           temp_data = (seqb_buffer[n]>>4) & 0x00000FFF;
    234.           printf("ADC channel %d data was %d\r\n", n, temp_data);
    235.                                        
    236.                                         NOKIA5110_display_8x6_text (0, lcd_n, "ADC");
    237.                                         sprintf(lcd_chr,"%2d",n);
    238.                                         NOKIA5110_display_8x6_text (18, lcd_n, lcd_chr);
    239.                                         NOKIA5110_display_8x6_text (30, lcd_n, ": 0x");
    240.                                         sprintf(lcd_chr,"%4d",temp_data);
    241.                                         NOKIA5110_display_8x6_text (54, lcd_n, lcd_chr);
    242.                                         lcd_n++;
    243.         }
    244.       }
    245.     }
    246.                 else
    247.                 {
    248.                         printf("\r\nInput error, please input again! \r\n");;
    249.                 }


    250.     // Put the external pins back to '1'
    251.     //LPC_GPIO_PORT->SET0 = 0x08010000;      // Set P0.27, P0.16 to '1'
    252.                 LPC_GPIO_PORT->SET0 = 0x00018000;      // Set P0.15, P0.16 to '1'
    253.                
    254.   } // end of while 1        

    255. } // end of main
    复制代码
    在代码中标注红色时出现问题,全乱了,下面截图说明。选中的蓝色字部分为添加或修改的程序。
            
    添加nokia5110 LCD函数库支持
    傲游截图20170107222801.jpg


    之前默认是\n\r,结果打印不换行,修改成“\r\n
    傲游截图20170107223324.jpg


    lcd显示行计数和字符串缓存
    傲游截图20170107223411.jpg


    原本是P0.27,改为P0.15。因为nokia5110 LCD显示用了5个IO,从P0.24到P0.28。
    傲游截图20170107223427.jpg


    把ADC6通道从seqa换到了seqb,这样匀一下方便显示
    傲游截图20170107223447.jpg


    在while之前,对LCD初始化并显示,串口也打印部分信息
    傲游截图20170107223504.jpg


    在seqa中,每次进入seqa时,清屏LCD
    傲游截图20170107223519.jpg


    对seqa中通道及电压在LCD上显示。245行有改动,NOKIA5110_display_8x6_text (30, lcd_n, ": ");
    傲游截图20170107223549.jpg


    改成判断字符'b',这样程序有效的字符只有'a'和'b'
    傲游截图20170107223619.jpg


    在seqb中,每次进入seqb时,清屏LCD
    傲游截图20170107223632.jpg


    同上,281行有改动,NOKIA5110_display_8x6_text (30, lcd_n, ": ");
    傲游截图20170107223655.jpg


    输入字符除‘a’、'b'外,都显示输入错误提示。
    傲游截图20170107223716.jpg


            实验连线,P0.15、P0.16分别与P0.11、P0.10连接,P0.24到P0.28接Nokia5110 LCD。模拟电压是通过LPC824 Lite板卡给提供的,存在干扰,但能看出AD效果来。P0.06接LPC824 Lite的电位器管脚,地线不用连(因为在LPC824 Breakout板上只有一根地线共LCD用了),通过USB共地。
            原理图接线
             傲游截图20170107231727.jpg


            实物连接,全家福。
             IMG_20170107_230502.jpg


            下载程序,复位后开始跑程序,串口终端显示。
             傲游截图20170107225507.jpg

           傲游截图20170107230655.jpg


             LCD显示
             IMG_20170107_230646.jpg


            输入'a'+空格,后开始seqa AD转换,结果显示在串口终端和LCD上
             傲游截图20170107230840.jpg


             LCD显示
             IMG_20170107_230824.jpg


            输入'b'+空格,后开始seqb AD转换,结果显示在串口终端和LCD上
             傲游截图20170107230926.jpg


            LCD显示结果
             IMG_20170107_230906.jpg


            LPC824 Breakout AD转换,结果成功显示在串口终端打印,并成功在LCD上显示。完美收工^_^。

            依照惯例, 修改后工程文件打包附上。
             LPC824_Example_Code_Bundle_Keil_r1.0(201701072334).rar (2.34 MB, 下载次数: 8)



    已有 2 人评分 收起 理由
    EEboard爱板网 + 21 3周发帖养成记 奖励
    loveeeboard + 40

    总评分:  + 61   查看全部评分

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    关闭

    站长推荐上一条 /2 下一条

    手机版|爱板网 |网站地图  

    GMT+8, 2017-11-25 19:24 , Processed in 0.277732 second(s), 15 queries , Memcache On.

    苏公网安备 32059002001056号

    Powered by Discuz!

    回顶部