• MSP430F5529库函数——模数转换模块(ADC12)软件触发


    需提前观看:MSP430F5529库函数学习——串口

     

    目录

    代码

    ADC初始化部分

    引脚复位

    ADC12_A_init()

    函数声明

    baseAddress

    sampleHoldSignalSourceSelect

    clockSourceSelec

    clockSourceDivider

    ADC12_A_enable()

    ADC12_A_setupSamplingTimer()

    ADC12_A_configureMemory()

    memoryBufferControlIndex

     inputSourceSelect

    positiveRefVoltageSourceSelect和negativeRefVoltageSourceSelect

    endOfSequence

    电压信号读取部分

    ADC12_A_startConversion()

    函数声明

    baseAddress

    startingMemoryBufferIndex

    conversionSequenceModeSelect

    ADC12_A_isBusy()

    ADC12_A_getResults()

    return


    我这里的代码意思是利用P6.0口作为ADC采集,利用软件触发的方式进行采集信号。每过1S采集一次ADC信号。并将ADC的值转换为电压值发送给上位机。

    代码

    1. #include "driverlib.h"
    2. #include <string.h>
    3. #include <stdarg.h>
    4. #include <stdio.h>
    5. #define MCLK_IN_HZ 1000000
    6. #define delay_us(x) __delay_cycles((MCLK_IN_HZ/1000000*(x)))
    7. #define delay_ms(x) __delay_cycles((MCLK_IN_HZ/1000*(x)))
    8. void setupADC(void);
    9. unsigned long readADC(void);
    10. void UART_printf(uint16_t baseAddress, const char *format,...);
    11. void Usart1_Init();
    12. //-------------------------------- m a i n -----------------------------------
    13. int main(void)
    14. {
    15. WDT_A_hold(WDT_A_BASE);
    16. Usart1_Init();
    17. setupADC();
    18. while(1)
    19. {
    20. delay_ms(1000);
    21. UART_printf(USCI_A1_BASE,"Result = %d mV\n", readADC());
    22. }
    23. }
    24. //----------------------------- s e t u p A D C -------------------------------
    25. void setupADC(void){
    26. #define ADCpin GPIO_PORT_P6,GPIO_PIN0
    27. GPIO_setAsPeripheralModuleFunctionOutputPin(ADCpin); // 复位P6.0
    28. //Initialize the ADC12_A Module
    29. /*
    30. * ADC12_A模块的基址
    31. * 软件触发
    32. * 使用MODOSC 5MHZ数字振荡器作为时钟源
    33. * 一分频
    34. */
    35. ADC12_A_init(ADC12_A_BASE,ADC12_A_SAMPLEHOLDSOURCE_SC, ADC12_A_CLOCKSOURCE_ADC12OSC, ADC12_A_CLOCKDIVIDER_1); //软件触发,内部振荡器MODCLK作为时钟
    36. ADC12_A_enable(ADC12_A_BASE); //启用ADC12_A模块
    37. //设置并启用采样定时器脉冲,这里是使用的软件触发的形式,所以选择失能
    38. ADC12_A_setupSamplingTimer(ADC12_A_BASE,ADC12_A_CYCLEHOLD_16_CYCLES,ADC12_A_CYCLEHOLD_16_CYCLES,ADC12_A_MULTIPLESAMPLESDISABLE);
    39. ADC12_A_configureMemoryParam param = {0};
    40. param.memoryBufferControlIndex = ADC12_A_MEMORY_0; //将内存缓冲配置为MEMORY_0
    41. param.inputSourceSelect = ADC12_A_INPUT_A0; //将输入A0映射到内存缓冲区0,因为P6.0引脚对应A0
    42. param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC; //正电压为AVcc
    43. param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS; //负电压为AVss
    44. param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE; //单通道转换
    45. ADC12_A_configureMemory(ADC12_A_BASE,&param); //
    46. }
    47. //----------------------------- r e a d A D C --------------------------------
    48. unsigned long readADC(void){
    49. //开始从MEMORY_0中进行单通道连续转换
    50. ADC12_A_startConversion(ADC12_A_BASE,ADC12_A_MEMORY_0,ADC12_A_SINGLECHANNEL);
    51. while(ADC12_A_isBusy(ADC12_A_BASE) == ADC12_A_BUSY){
    52. // 等待转换完成
    53. }
    54. //读取ADC转换之后寄存器的值
    55. long result = ADC12_A_getResults(ADC12_A_BASE, ADC12_A_MEMORY_0);
    56. //将其转化为单位为mv的电压值
    57. return (3220 * result) / 4096; // 3320是测量的Vss
    58. }
    59. void UART_printf(uint16_t baseAddress, const char *format,...)
    60. {
    61. uint32_t length;
    62. va_list args;
    63. uint32_t i;
    64. char TxBuffer[128] = {0};
    65. va_start(args, format);
    66. length = vsnprintf((char*)TxBuffer, sizeof(TxBuffer)+1, (char*)format, args);
    67. va_end(args);
    68. for(i = 0; i < length; i++)
    69. USCI_A_UART_transmitData(baseAddress, TxBuffer[i]);
    70. }
    71. //9600
    72. void Usart1_Init()
    73. {
    74. //P4.4=UCA1TXD P4.5=UCA1RXD
    75. GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN5+GPIO_PIN4);
    76. USCI_A_UART_initParam param1 = {0};
    77. param1.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
    78. param1.clockPrescalar = 6;
    79. param1.firstModReg = 13;
    80. param1.secondModReg = 0;
    81. param1.parity = USCI_A_UART_NO_PARITY; //无校验位
    82. param1.msborLsbFirst = USCI_A_UART_LSB_FIRST; //低位先行
    83. param1.numberofStopBits = USCI_A_UART_ONE_STOP_BIT; //1停止位
    84. param1.uartMode = USCI_A_UART_MODE;
    85. param1.overSampling = USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;
    86. if (STATUS_FAIL == USCI_A_UART_init(USCI_A1_BASE, &param1)){
    87. return;
    88. }
    89. //Enable UART module for operation
    90. USCI_A_UART_enable(USCI_A1_BASE);
    91. //Enable Receive Interrupt
    92. USCI_A_UART_clearInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
    93. USCI_A_UART_enableInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
    94. }

    ADC初始化部分

    引脚复位

    首先我们复位P6.0,为什么复位P6.0。因为ADC具有12个外部采集功能的引脚,如下。

     

    ADC12_A_init()

    我们这里采用软件触发的方式进行ADC采集。软件触发的意思是,需要我们在写程序的时候,写入一个ADC开始采集的程序,他才会采集电压信号。ADC采集的时钟源是使用MODOSC 5MHZ数字振荡器。不进行分频 

    ADC12_A_init(ADC12_A_BASE,ADC12_A_SAMPLEHOLDSOURCE_SC, ADC12_A_CLOCKSOURCE_ADC12OSC, ADC12_A_CLOCKDIVIDER_1);  //软件触发,内部振荡器MODCLK作为时钟

    函数声明

    函数声明如下,这里返回的是一个布尔值。如果ADC初始化成功了返回STATUS_SUCCESS(也就是1),如果ADC初始化失败了返回0。我们没有进行接收他的数值,一般不需要接收,因为ADC初始化失败的可能性很小。

    bool ADC12_A_init (uint16_t baseAddress,uint16_t sampleHoldSignalSourceSelect, uint8_t clockSourceSelect,uint16_t clockSourceDivider)

    baseAddress

    ADC12只有一个基地址

    ADC12_A_BASE

    sampleHoldSignalSourceSelect

    选择触发信号ADC进行电压采集有四种触发方式,参数如下

    1. #define ADC12_A_SAMPLEHOLDSOURCE_SC (ADC12SHS_0)//软件触发
    2. #define ADC12_A_SAMPLEHOLDSOURCE_1 (ADC12SHS_1)//定时器1触发
    3. #define ADC12_A_SAMPLEHOLDSOURCE_2 (ADC12SHS_2)//定时器2触发
    4. #define ADC12_A_SAMPLEHOLDSOURCE_3 (ADC12SHS_3)//定时器3触发

    第一种是ADC12SC触发,也就是软件触发。

    二三四种是利用定时器触发ADC采集,定时器触发的好处是,我们不需要占用CPU,让他自己每隔一段时间主动触发ADC采集。但是缺点是,不够灵活,他不能做到我们想采集电压就采集,不想采集就不采集。

    至于我们想知道这个ADC12SHSx的定时器采集是哪几个定时器,不同芯片情况不同我们需要看引脚功能数据表,按Ctrl+F搜索ADC12SHSx即可出现如下(注意,我这里只提供MSP430F5529的,其他型号的自己去找)。

    clockSourceSelec

    这个是选择ADC的时钟源,一般选择内部震荡器

    1. #define ADC12_A_CLOCKSOURCE_ADC12OSC (ADC12SSEL_0)//内部振荡器
    2. #define ADC12_A_CLOCKSOURCE_ACLK (ADC12SSEL_1)
    3. #define ADC12_A_CLOCKSOURCE_MCLK (ADC12SSEL_2)
    4. #define ADC12_A_CLOCKSOURCE_SMCLK (ADC12SSEL_3)

    clockSourceDivider

    选择分频次数,一般选择不分频。

    1. #define ADC12_A_CLOCKDIVIDER_1 (ADC12DIV_0)
    2. #define ADC12_A_CLOCKDIVIDER_2 (ADC12DIV_1)
    3. #define ADC12_A_CLOCKDIVIDER_3 (ADC12DIV_2)
    4. #define ADC12_A_CLOCKDIVIDER_4 (ADC12DIV_3)
    5. #define ADC12_A_CLOCKDIVIDER_5 (ADC12DIV_4)
    6. #define ADC12_A_CLOCKDIVIDER_6 (ADC12DIV_5)
    7. #define ADC12_A_CLOCKDIVIDER_7 (ADC12DIV_6)
    8. #define ADC12_A_CLOCKDIVIDER_8 (ADC12DIV_7)
    9. #define ADC12_A_CLOCKDIVIDER_12 (ADC12DIV_2 + ADC12PDIV)
    10. #define ADC12_A_CLOCKDIVIDER_16 (ADC12DIV_3 + ADC12PDIV)
    11. #define ADC12_A_CLOCKDIVIDER_20 (ADC12DIV_4 + ADC12PDIV)
    12. #define ADC12_A_CLOCKDIVIDER_24 (ADC12DIV_5 + ADC12PDIV)
    13. #define ADC12_A_CLOCKDIVIDER_28 (ADC12DIV_6 + ADC12PDIV)
    14. #define ADC12_A_CLOCKDIVIDER_32 (ADC12DIV_7 + ADC12PDIV)

    ADC12_A_enable()

    这个是用于启动ADC的,只需要传入ADC12_A_BASE就可以启动ADC12_A模块了。

    ADC12_A_setupSamplingTimer()

    这个跟定时器触发有关,所以不讲,只要记得第四个参数选择ADC12_A_MULTIPLESAMPLESDISABLE即可。因为我们是软件触发

    ADC12_A_configureMemory()

    这个需要传入ADC的基地址和结构体,基地址还是相同的。只讲结构体

    1. ADC12_A_configureMemoryParam param = {0};
    2. param.memoryBufferControlIndex = ADC12_A_MEMORY_0; //将内存缓冲配置为MEMORY_0
    3. param.inputSourceSelect = ADC12_A_INPUT_A0; //将输入A0映射到内存缓冲区0,因为P6.0引脚对应A0
    4. param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC; //正电压为AVcc
    5. param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS; //负电压为AVss
    6. param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE; //单通道转换

    memoryBufferControlIndex

    这个是负责配置我们ADC采集之后的数值存入哪里。如果是单通道随便选择一个就可以了,建议选择通道ADC12_A_MEMORY_0

    1. #define ADC12_A_MEMORY_0 (0x0)
    2. #define ADC12_A_MEMORY_1 (0x1)
    3. #define ADC12_A_MEMORY_2 (0x2)
    4. #define ADC12_A_MEMORY_3 (0x3)
    5. #define ADC12_A_MEMORY_4 (0x4)
    6. #define ADC12_A_MEMORY_5 (0x5)
    7. #define ADC12_A_MEMORY_6 (0x6)
    8. #define ADC12_A_MEMORY_7 (0x7)
    9. #define ADC12_A_MEMORY_8 (0x8)
    10. #define ADC12_A_MEMORY_9 (0x9)
    11. #define ADC12_A_MEMORY_10 (0xA)
    12. #define ADC12_A_MEMORY_11 (0xB)
    13. #define ADC12_A_MEMORY_12 (0xC)
    14. #define ADC12_A_MEMORY_13 (0xD)
    15. #define ADC12_A_MEMORY_14 (0xE)
    16. #define ADC12_A_MEMORY_15 (0xF)

     inputSourceSelect

    这个是选择我们采集的电压通道口,上面说了ADC只有12个外部信号采集口。因为我们上面复位的是P6.0所以这里是选择ADC12_A_INPUT_A0。

     可选参数如下

    1. #define ADC12_A_INPUT_A0 (ADC12INCH_0)
    2. #define ADC12_A_INPUT_A1 (ADC12INCH_1)
    3. #define ADC12_A_INPUT_A2 (ADC12INCH_2)
    4. #define ADC12_A_INPUT_A3 (ADC12INCH_3)
    5. #define ADC12_A_INPUT_A4 (ADC12INCH_4)
    6. #define ADC12_A_INPUT_A5 (ADC12INCH_5)
    7. #define ADC12_A_INPUT_A6 (ADC12INCH_6)
    8. #define ADC12_A_INPUT_A7 (ADC12INCH_7)
    9. #define ADC12_A_INPUT_A8 (ADC12INCH_8)
    10. #define ADC12_A_INPUT_A9 (ADC12INCH_9)
    11. #define ADC12_A_INPUT_TEMPSENSOR (ADC12INCH_10)
    12. #define ADC12_A_INPUT_BATTERYMONITOR (ADC12INCH_11)
    13. #define ADC12_A_INPUT_A12 (ADC12INCH_12)
    14. #define ADC12_A_INPUT_A13 (ADC12INCH_13)
    15. #define ADC12_A_INPUT_A14 (ADC12INCH_14)
    16. #define ADC12_A_INPUT_A15 (ADC12INCH_15)

    positiveRefVoltageSourceSelect和negativeRefVoltageSourceSelect

     这两个是选择参考电压的,可以是内部电压为参考电压,也可以是外部的。本人只会内部的,所以只讲内部电压作为参考电压。直接如下即可

    1. param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC; //正电压为AVcc,为3320mV
    2. param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS; //负电压为AVss,为0mV

    endOfSequence

    这个ADC采集可以是序列通道采集和单通道采集。我这里选择的是单通道采集,序列通道采集。序列通道采集就是很多个通道一起采集信号。我这里只讲单通道采集

    1. #define ADC12_A_NOTENDOFSEQUENCE (!(ADC12EOS))//单通道采集
    2. #define ADC12_A_ENDOFSEQUENCE (ADC12EOS)//多通道采集

    电压信号读取部分

    ADC12_A_startConversion()

    这里是开启ADC采集的。

    函数声明

    void ADC12_A_startConversion (uint16_t baseAddress, uint16_t startingMemoryBufferIndex, uint8_t conversionSequenceModeSelect)

    baseAddress

    同上

    startingMemoryBufferIndex

    设置需要开始转换的信号。因为我们之前将ADC采集的信号存入MEMORY_0,所以这里选择ADC12_A_MEMORY_0。可选参数如下

    1. #define ADC12_A_MEMORY_0 (0x0)
    2. #define ADC12_A_MEMORY_1 (0x1)
    3. #define ADC12_A_MEMORY_2 (0x2)
    4. #define ADC12_A_MEMORY_3 (0x3)
    5. #define ADC12_A_MEMORY_4 (0x4)
    6. #define ADC12_A_MEMORY_5 (0x5)
    7. #define ADC12_A_MEMORY_6 (0x6)
    8. #define ADC12_A_MEMORY_7 (0x7)
    9. #define ADC12_A_MEMORY_8 (0x8)
    10. #define ADC12_A_MEMORY_9 (0x9)
    11. #define ADC12_A_MEMORY_10 (0xA)
    12. #define ADC12_A_MEMORY_11 (0xB)
    13. #define ADC12_A_MEMORY_12 (0xC)
    14. #define ADC12_A_MEMORY_13 (0xD)
    15. #define ADC12_A_MEMORY_14 (0xE)
    16. #define ADC12_A_MEMORY_15 (0xF)

    conversionSequenceModeSelect

    这个是选择ADC开启的模式。有四种模式,如下。

    说白了就是一个多通道和单通道,多通道可以多个通道一起进行ADC电压信号采集,比如P6.0和P6.1同时进行ADC电压采集,而单通道只有一个引脚进行ADC电压信号采集。

    然后单次采样和多次采样的区别是,如果我们选择的单次采样,那么每次进行ADC采样都需要一次触发。但是如果是多次采样,那么我们只需要一次触发,那么他就会持续采样转换,如果此次电压转换之后的信号不马上读取,会被下一次转换之后的信号覆盖。因为我们这里选择的软件触发,我们我个人建议选择单次采样,这样我们的电压采样转换的信号就不会被覆盖,同时可以降低功耗。

    1. #define ADC12_A_SINGLECHANNEL (ADC12CONSEQ_0)//单通道单次采样
    2. #define ADC12_A_SEQOFCHANNELS (ADC12CONSEQ_1)//多通道单次采样
    3. #define ADC12_A_REPEATED_SINGLECHANNEL (ADC12CONSEQ_2)//单通道循环采样
    4. #define ADC12_A_REPEATED_SEQOFCHANNELS (ADC12CONSEQ_3)//多通道循环采样

    ADC12_A_isBusy()

    我们电压信号采集之后,需要给他一个时间等待将电压信号转换为数字信号(01这种)。当还在转换过程的时候,他会返回ADC12_A_BUSY。所以我们需要持续调用这个函数,等待转换结束。

    ADC12_A_getResults()

    获取当前ADC采样之后的值,因为我们上面选择是将转换信号存入MEMORY_0,所以这里选择ADC12_A_MEMORY_0。

    return

    我们最后需要返回一个值。因为我们上面选择的参考电压为AVcc和AVss。所以电压范围为0-3320mV。因为我们这个ADC是一个12位的,所以寄存器中的存储最大值是2^{12}=4096。当采集到的电压为0V时候,寄存器为0。当采集到电压为3320mV的时候,寄存器的值为4095。所以我们返回值为(3220 * result) / 4096;,至于为什么是4096,因为我们是从0开始计算。

    串口配置

    注意,这部分我就提醒一下。我们是需要进行浮点数据打印的,所以我们看MSP430F5529库函数学习——串口的时候,需要按照浮点数据打印这一部分配置!

  • 相关阅读:
    SpringBoot 集成 Canal 实现监听MySQL表数据
    MYSQL ORDER BY
    【Go入门】struct类型
    cutree 算法
    开源跨平台视频编辑器 Shotcut 22.06.23 下载安装
    【从零开始学习Redis | 第五篇】基于布隆过滤器解决Redis的穿透问题
    智慧物流解决方案-最新全套文件
    vulhub中GitLab 任意文件读取漏洞复现(CVE-2016-9086)
    基于SpringBoot的防疫物资管理平台设计与实现
    Netty基础入门和基本使用
  • 原文地址:https://blog.csdn.net/qq_63922192/article/details/127831691