【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验

02-29 阅读 0评论

上一课:

【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验,【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,访问,安装,第1张
(图片来源网络,侵删)

【小黑嵌入式系统第十五课】μC/OS-III程序设计基础(四)——消息队列(工作方式&数据通信&生产者消费者模型)、动态内存管理、定时器管理



前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站:人工智能

【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验



文章目录

    • 1 实验目的
    • 2 实验要求
    • 3 实验设备
    • 4 实验原理
    • 5 硬件设计
      • 5.1 ADC
      • 5.2 时钟
      • 5.3 PGA
      • 6 软件设计
        • 6.1 总体设计
        • 6.2 详细设计
          • App.c
          • App_cfg.h
          • ISR.c
          • 7 测试与分析
          • 8 结论与问题讨论

            1 实验目的

            • 理解并掌握基于μC/OS-III的应用程序框架;
            • 理解任务管理的概念和方法,并熟练其基本应用;
            • 理解共享资源的概念,掌握其管理方法;
            • 理解信号量的概念与使用方法,并熟练其基本应用;
            • 完成基于μC/OS-III的实用电压计的应用程序设计。

              2 实验要求

              1. 通过示例项目“uCOS-III 移植至 PSoC 5LP 的入门示例”和“uCOS-III 中断入门项目示例”,熟悉并掌握PSoC 5LP平台上μC/OS-III应用程序的框架结构;
              2. 通过示例项目“Micrium_CY8CKIT-050B_uCOS-III-LCDMutex_GNU(P

                SoC Creator 4.0).rar”,学习理解共享资源的概念,掌握其在μC/OS-III中的管理方法;

              3. 通过示例项目“uCOS-III 中断入门项目示例”和“Micrium_CY8CKIT-

                050B_uCOS-III-Sem-ISR_GNU(PSoC Creator 4.0).rar”,学习理解信号量的概念及其使用方法;

              4. 编写一个基于μC/OS-III的实用电压计的应用程序,要求:

                a. 使用片内的SAR ADC1(或者自己设计实现的SAR ADC),设为8位分辨率,测量电位器R56的抽头电压。有三档量程:2V、200mV、20mV,通过SW3切换量程。测量结果显示在LCD的第一行;

                【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验,【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,访问,安装,第3张
                (图片来源网络,侵删)

                b. 使用片内的SAR ADC0,设为12位分辨率,也同时测量电位器R56的抽头电压。只有一档固定量程:2V。测量结果显示在LCD的第二行;

                c. 具有显示保持功能。SW2用作显示保持功能按键,LED4用作显示保持状态的指示;

                d. 通过预先分析和实际测量,得出多量程电压计的各档电压测量精度结论,并与市场上的三位半数字万用表的DC精度比较。

                更多的改进方向:

                e. 增加一档量程:自动

              3 实验设备

              CY8CKIT-050实验板

              安装了PSoC Creator软件的PC机

              【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验,【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,访问,安装,第4张
              (图片来源网络,侵删)

              4 实验原理

              基本概念:

              1. 前后台系统

                对基于芯片的开发来说,应用程序一般是一个无限的循环,可称为前后台系统或超循环系统。

                【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验

                前后台系统结构简单,很多基于微处理器的产品都采用了前后台系统设计,例如微波炉、电话机、玩具等。而在一些基于微处理器的应用中,从省电的角度出发,平时微处理器处在停机状态,所有事都靠中断服务来完成。

              2. 操作系统

                操作系统是计算机中最基本的程序。操作系统负责计算机系统中全部软硬资源的分配与回收、控制与协调等并发的活动;操作系统提供应用程序接口,使用户获得良好的工作环境;操作系统为用户扩展新的系统功能提供软件平台。

              3. 实时操作系统(RTOS)

                实时操作系统是一段在嵌入式系统启动后首先执行的背景程序,用户的应用程序是运行于RTOS之上的各个任务,RTOS根据各个任务的要求,进行资源(包括CPU、存储器、外设等)管理、消息管理、任务调度、异常处理等工作。

                在RTOS支持的系统中, 每个任务均有一个优先级,RTOS根据各个任务的优先级,动态地切换各个任务,保证对实时性的要求。

                实时操作系统包含实时内核,以及其它高级的服务如:文件管理、协议栈、图形用户接口(GUI)等。

              4. 内核

                多任务系统中,内核负责管理各个任务,或者说为每个任务分配CPU时间,并且负责任务之间的通信。内核提供的最基本服务是任务切换。使用实时内核可以大大简化应用系统的设计,因为实时内核允许将应用分成若干个任务,由实时内核来管理它们。

                内核需要消耗一定的系统资源,比如2%~5%的CPU运行时间、RAM和ROM等。

                内核还提供一些必不可少的系统服务,如信号量、消息队列、延时等。

              5. 任务

                一个任务,也称作一个线程,是一段简单的程序,该程序可以认为CPU完全属于该程序自己。每个任务被赋予一定的优先级,有它自己的一套CPU寄存器和自己的栈空间。

                实时应用程序的设计过程,包括如何把问题分割成多个任务,每个任务都是整个应用的某一部分。

              6. 任务优先级

                任务的优先级是表示任务被调度的优先程度。每个任务都具有优先级。任务越重要,赋予的优先级应越高,越容易被调度进入运行态。

              7. 任务切换

                当多任务内核决定运行另外的任务时,它保存正在运行任务的当前状态,即CPU寄存器中的全部内容。这些内容保存在任务的当前状态保存区,即任务自已的栈之中。入栈工作完成以后,就把下一个将要运行的任务的当前状态从其栈中重新装入CPU的寄存器,并开始下一个任务的运行。这个过程就称为任务切换。

                这个过程增加了应用程序的额外负荷。CPU的内部寄存器越多,额外负荷就越重。做任务切换所需要的时间取决于CPU有多少寄存器要入栈。

              8. 调度

                调度是内核的主要职责之一。调度就是决定该轮到哪个任务运行了。多数实时内核是基于优先级调度法的。每个任务根据其重要程序的不同被赋予一定的优先级。基于优先级的调度法指CPU总是让处在就绪态的优先级最高的任务先运行。

                然而究竟何时让高优先级任务掌握CPU的使用权,有两种不同的情况,这要看用的是什么类型的内核,是非抢占式的还是抢占式的内核。

              9. 非抢占式(合作式)内核

                非抢占式内核要求每个任务自我放弃CPU 的所有权。非抢占式调度法也称作合作型多任务,各个任务彼此合作共享一个CPU。

                异步事件还是由中断服务来处理。中断服务可以使一个高优先级的任务由挂起(Pending,或译为“等待” )状态变为就绪状态。但中断服务以后CPU控制权还是回到原来被中断了的那个任务,直到该任务主动放弃CPU的使用权时,那个高优先级的任务才能获得CPU的使用权。

              10. 抢占式(可剥夺式)内核

                当系统响应时间很重要时,要使用抢占式内核。因此绝大多数商业上销售的实时内核都是抢占式内核。最高优先级的任务一旦就绪,总能得到CPU的控制权。当一个运行着的任务使一个比它优先级高的任务进入了就绪状态,当前任务的CPU使用权就被剥夺了,或者说被挂起了,那个高优先级的任务立刻得到了CPU的控制权。

                如果是中断服务程序使一个高优先级的任务进入就绪态,中断完成时,中断了的任务将被挂起,优先级高的那个任务开始运行。

              11. 中断

                中断是一种硬件机制,用于通知CPU有个异步事件发生了。中断一旦被识别,CPU保存部分(或全部)上下文即部分或全部寄存器的值,跳转到专门的子程序,称为中断服务程序(ISR)。中断服务程序做事件处理,处理完成后,程序回到:

                【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验1.在前后台系统中,程序回到后台程序;

                2.对非抢占式内核而言,程序回到被中断了的任务;

                3.对抢占式内核而言,让进入就绪态的优先级最高的任务开始运行。

              12. 时钟节拍

                时钟节拍是特定的周期性中断。这个中断可以看作是系统心脏的脉动。中断之间的时间间隔取决于不同应用,一般在10ms到200ms之间。时钟的节拍式中断使得内核可以将任务延时若干个整数时钟节拍,以及当任务在等待事件发生时,提供等待超时的依据。

                时钟节拍率越快,系统的额外开销就越大。

              5 硬件设计

              【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验

              Vin_Pot 输入电压同时送入上下两路 SAR ADC。SAR ADC 0 设为 12 位分辨率,2.048V 的固定 量程,将它作为 SAR ADC 1 的测量结果准确性对照。SAR ADC 1 设为 8 位分辨率,输入范围设为 0~2.048V。

              为了尽量实现准确的测量,应让 Vin_Pot 的变化范围与 SAR ADC 1 的输入范围尽量匹配,为此 使用了两个可编程增益放大器 PGA_1 和 PGA_2 对小输入电压进行放大。针对 Vin_Pot 的不同变化 范围(3 个量程),两个 PGA 的增益设置如上图所示,2000mV 量程时总增益为 1,200mV 量程时总增益为 8,20mV 量程时总增益为 96。

              200mV 量程时这里将总增益安排为 8 而不是 10(因为 PGA 并没有 1x10 或者 2x5 的增益配置可选),此时Vin_Pot范围在0~256mV时与SAR ADC 1的输入范围刚好匹配,但程序只处理0~200mV的范围,即使用了 SAR ADC 1 的 80% F.S.。

              20mV 量程时将总增益安排为 96 而不是 100,此时 Vin_Pot 范围在 0~21.3mV 时与 SAR ADC 1的输入范围刚好匹配,但程序只处理 0~20mV 的范围,即使用了 SAR ADC 1 的 94% F.S.。这样可以让 20mV 和 200mV 量程之间有一个重叠(20~21.3mV),当使用自动量程测量时,避免被测电压出现在相邻量程的交界处时显示结果跳动频繁。如上所述 200mV 和 2000mV 量程之间也有重叠(200~256mV)。

              按键状态通过 D 触发器,每隔 20ms(1/50Hz)采样一次,q 为硬件消抖后的输出,提供给中断。中断的触发类型设为上升沿触发。按键的每次按下时刻,触发一次中断。

              5.1 ADC

              【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验

              5.2 时钟

              【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验

              5.3 PGA

              【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验

              6 软件设计

              6.1 总体设计

              app.c 中定义了:#define DISPHOLD_STATUS() (LED4_Read()==1) 通过 DISPHOLD_STATUS()可知当前的显示保持状态,当值为 0(DEF_FALSE)时, 任务正常 进行测量和结果显示;当值为 1(DEF_TRUE)时,不进行测量和结果显示。

              App_TaskADC12()是第一个创建的用户任务,负责通过 SAR ADC 0(12 位分辨率)测量输 入电压及结果显示,以及 SW2 显示保持按键事件的处理。当前的显示保持状态由 LED4 指示。在非显示保持状态时,进行测量电压、过量程判断、LCD 显示工作。

              App_TaskMyADC8()是由 App_TaskADC12()创建的第二个用户任务,负责通过 SAR ADC 1 测量输入电压及结果显示,以及 SW3 量程选择按键事件的处理。在非显示保持状态时,若当前量程选择为非自动,则按指定量程测量电压, 再显示测量值;若当前量程选择为自动,则先以最大量程粗测一次,从而确定被测电压落在 哪个量程最佳,然后以最佳量程再测一次,再显示后者测量值。

              SW2、SW3 按键按下时刻分别会触发 isr_sw2 和 isr_sw3 中断,在中断服务函数中,分别给任务 App_TaskADC12() 、 App_TaskMyADC8() 发信号量。 下列代码以 isr_sw2 中断和任务App_TaskADC12()为例,任务中等待信号量, 不管当前是否收到信号量立即返回,根据返回的错误代码 os_err 值判断当前是否收到信号量,若收到则更改显示保持状态指示。

              6.2 详细设计

              App.c
              /*INCLUDE FILES*/ 
              #include  
              #include  
              /* LOCAL DEFINES*/ 
              #define MAX_SAMPLE 8 
              /* 偏移误差值 */ 
              #define DC_OFFSET_MV_2000MV 2 
              #define DC_OFFSET_100uV_200MV 10 
              #define DC_OFFSET_10uV_20MV 0 
              /* 增益误差值 */ 
              #define DC_GAIN_CAL_FACTOR_2000MV 1.00 
              #define DC_GAIN_CAL_FACTOR_200MV 0.99 
              #define DC_GAIN_CAL_FACTOR_20MV 0.95 
              /* 测量范围 */ 
              #define RANGE_2000MV 0 
              #define RANGE_200MV 1 
              #define RANGE_20MV 2 
              #define RANGE_AUTO 36 
              #define RANGE_NUM_MAX 4 
              /* 增益*/ 
              #define Vin_GAIN_2000MV 1 
              #define Vin_GAIN_200MV 8 
              #define Vin_GAIN_20MV 96 
              #define DISPHOLD_STATUS() (LED4_Read()==1) 
              /*GLOBAL VARIABLES*/ 
              OS_SEM sem_sw2, sem_sw3; 
              /*LOCAL VARIABLES*/ 
              static OS_TCB App_TaskADC12TCB; 
              static CPU_STK App_TaskADC12Stk[APP_CFG_TASK_ADC12_STK_SIZE]; 
              static OS_TCB App_TaskMyADC8TCB; 
              static CPU_STK App_TaskMyADC8Stk[APP_CFG_TASK_MyADC8_STK_SIZE]; 
              static OS_MUTEX mutex_LCD; 
              /*FUNCTION PROTOTYPES*/ 
              static void App_TaskADC12 (void *p_arg); 
              static void App_TaskMyADC8 (void *p_arg); 
              static void App_TaskCreate (void); 
              static void App_ObjCreate (void); 
              static CPU_INT16U SAR_ADC12_GetResult (void); 
              static CPU_INT16U My_SAR_ADC_GetResult (CPU_INT08U range); 
              /*Main函数*/ 
              int main (void) 
              { 
              OS_ERR os_err;7 
              BSP_PreInit(); 
              CPU_Init(); 
              OSInit(&os_err); 
              OSTaskCreate((OS_TCB *)&App_TaskADC12TCB, 
              (CPU_CHAR *)"ADC12", 
              (OS_TASK_PTR )App_TaskADC12, 
              (void *)0, 
              (OS_PRIO)APP_CFG_TASK_ADC12_PRIO, 
              (CPU_STK *)&App_TaskADC12Stk[0], 
              (CPU_STK_SIZE )APP_CFG_TASK_ADC12_STK_SIZE_LIMIT, 
              (CPU_STK_SIZE )APP_CFG_TASK_ADC12_STK_SIZE, 
              (OS_MSG_QTY )0, 
              (OS_TICK )0, 
              (void *)0, 
              (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), 
              (OS_ERR *)&os_err); 
              OSStart(&os_err); 
              static void App_TaskADC12 (void *p_arg) 
              { 
              OS_ERR os_err; 
              CPU_TS ts; 
              CPU_INT16U mVolts; 
              CPU_CHAR str[20]; 
              (void)p_arg; 
              BSP_PostInit(); 
              BSP_CPU_TickInit(); 
              #if (OS_CFG_STAT_TASK_EN > 0) 
              OSStatTaskCPUUsageInit(&err); 
              #endif 
              #ifdef CPU_CFG_INT_DIS_MEAS_EN 
              CPU_IntDisMeasMaxCurReset(); 
              #endif 
              App_TaskCreate(); 
              App_ObjCreate(); 
              /* Print the initial LCD and LED display */ 
              LCD_Position(0, 0); 
              LCD_PrintString("2000m"); 
              LCD_Position(1, 0); 
              LCD_PrintString("ADC12:");LED4_Write(0); 
              ADC_SAR_0_StartConvert(); 
               
              while (DEF_TRUE) 
              { 
              OSSemPend(&sem_sw2, 0, OS_OPT_PEND_NON_BLOCKING, &ts, &os_err); 
              if(os_err == OS_ERR_NONE) 
              { 
              /* 按下SW2,切换并指示显示保持状态 */ 
              LED4_Write(~LED4_Read()); 
              OSMutexPend(&mutex_LCD, 0, OS_OPT_PEND_BLOCKING, &ts, &os_err);
              if(os_err == OS_ERR_NONE) 
              { 
              LCD_Position(0, 6); 
              if(DISPHOLD_STATUS() == DEF_TRUE) 
              { 
              LCD_PutChar('H'); 
              } 
              else 
              { 
              LCD_PutChar(' '); 
              } 
              OSMutexPost(&mutex_LCD, OS_OPT_POST_NONE, &os_err); 
              } 
              } 
              if(DISPHOLD_STATUS() == DEF_FALSE) 
              { 
              mVolts = SAR_ADC12_GetResult(); 
              /* Print the measured voltage value */ 
              sprintf(str,"%4d mV", mVolts); 
              OSMutexPend(&mutex_LCD, 0, OS_OPT_PEND_BLOCKING, &ts, &os_err); 
              if(os_err == OS_ERR_NONE) 
              { 
              LCD_Position(1,9); 
              LCD_PrintString(str); 
              LCD_Position(1, 7); 
              if(mVolts >= 2048) 
              { 
              LCD_PutChar('^'); 
              } 
              else 
              { 
              LCD_PutChar(' '); 
              } 
              OSMutexPost(&mutex_LCD, OS_OPT_POST_NONE, &os_err); 
              // Release LCD Mutex 
              } 
              } 
              else 
              { 
              } 
              OSTimeDlyHMSM(0, 0, 0, 250, OS_OPT_TIME_HMSM_STRICT, &os_err); 
              // Wait 250ms, give CPU to other tasks 
              } 
              } 
              static void App_TaskMyADC8 (void *p_arg) 
              { 
              OS_ERR os_err; 
              CPU_TS ts; 
              CPU_INT08U volt_range = RANGE_2000MV; 
              CPU_INT08U volt_range_auto = RANGE_2000MV; 
              CPU_INT16U voltDigs; 
              /* 在中保留有效数字(删除小数点)毫伏、一百微伏或十微伏 */ 
              CPU_CHAR str[20]; 
              (void)p_arg; 
              while (DEF_TRUE) 
              {
              OSSemPend(&sem_sw3, 0, OS_OPT_PEND_NON_BLOCKING, &ts, &os_err); 
              if(os_err == OS_ERR_NONE) 
              { /* 如果按下SW3,则切换到下一个电压范围 */ 
              volt_range = (volt_range +1) % RANGE_NUM_MAX; 
              } 
              if(DISPHOLD_STATUS() == DEF_FALSE) 
              { 
              /* My SAR ADC8:获取八次连续转换的平均值 */ 
              if(volt_range != RANGE_AUTO) 
              { 
              /* Perform only one measurement with a fixed range */ 
              voltDigs = My_SAR_ADC_GetResult(volt_range); 
              } 
              else 
              { 
              /* Perform a rough measurement */ 
              volt_range_auto = RANGE_2000MV; 
              voltDigs = My_SAR_ADC_GetResult(volt_range_auto); 
              /* Determine the appropriate range and measure once again*/ 
              if(voltDigs >= 200) 
              // >=200 mV 
              { 
              } 
              else if(voltDigs >= 20) // 199~20 mV 
              { 
              volt_range_auto = RANGE_200MV; 
              voltDigs = My_SAR_ADC_GetResult(volt_range_auto); 
              } 
              else 
              // 19~0 mV 
              { 
              volt_range_auto = RANGE_20MV; 
              voltDigs = My_SAR_ADC_GetResult(volt_range_auto); 
              } 
              } 
              OSMutexPend(&mutex_LCD, 0, OS_OPT_PEND_BLOCKING, &ts, 
              &os_err); // Wait for LCD Mutex 
              if(os_err == OS_ERR_NONE) 
              { 
              /* 确定过电压状态并标记 */ 
              LCD_Position(0, 7); 
              str[0] = ' '; 
              if(voltDigs > 2000 && ((volt_range == RANGE_2000MV)|| \(volt_range == RANGE_AUTO && volt_range_auto 		== RANGE_2000MV))) 
              { 
              voltDigs = 2000; 
              // 避免显示超过测量范围的电压值 
              str[0] = '^'; 
              // 记录过电压标记 
              } 
              if(voltDigs*Vin_GAIN_200MV*10 > 2000 && volt_range == RANGE_200MV) 
              { 
              voltDigs = 200/Vin_GAIN_200MV ; 
              str[0] = '^'; 
              } 
              if((voltDigs+1)*Vin_GAIN_20MV*100 > 2000 && volt_range == 
              RANGE_20MV) 
              { 
              voltDigs = 20; 
              str[0] = '^'; 
              } 
              LCD_PutChar(str[0]); 
              /* Print the measured voltage value */ 
              LCD_Position(0, 0); 
              switch(volt_range) 
              { 
              case RANGE_2000MV: 
              LCD_PrintString("2000m"); 
              sprintf(str, " %4d mV", voltDigs); 
              break; 
              case RANGE_200MV: 
              LCD_PrintString("200m "); 
              sprintf(str, "%3d.%01d mV", 
              voltDigs*Vin_GAIN_200MV, voltDigs%Vin_GAIN_200MV); 
              break; 
              case RANGE_20MV: 
              LCD_PrintString("20m "); 
              if(voltDigs>=20) 
              sprintf(str, "20.%02d mV", 
              voltDigs%Vin_GAIN_20MV); 
              else 
              sprintf(str, "%2d.%02d mV", voltDigs*98, 
              voltDigs%Vin_GAIN_20MV); 
              break; 
              case RANGE_AUTO: 
              LCD_PrintString("AUTO"); 
              switch(volt_range_auto)13 
              { 
              case RANGE_2000MV: 
              LCD_PutChar('H'); 
              sprintf(str, " %4d mV", voltDigs); 
              break; 
              case RANGE_200MV: 
              LCD_PutChar('M'); 
              sprintf(str, "%3d.%01d mV", 
              voltDigs*Vin_GAIN_200MV, 	voltDigs%Vin_GAIN_200MV); 
              break; 
              case RANGE_20MV: 
              LCD_PutChar('L'); 
              sprintf(str, "f.%02d mV", 
              voltDigs*Vin_GAIN_20MV, 	voltDigs%Vin_GAIN_20MV); 
              break; 
              default: 
              break; 
              } 
              break; 
              default: 
              break; 
              } 
              LCD_Position(0, 8); 
              LCD_PrintString(str); 
              OSMutexPost(&mutex_LCD, OS_OPT_POST_NONE, &os_err); 
              // Release LCD Mutex 
              } 
              } 
              else 
              { 
              } 
              OSTimeDlyHMSM(0, 0, 0, 250, OS_OPT_TIME_HMSM_STRICT,&os_err); 
              // Wait 250ms, give CPU to other tasks 
              } 
              } 
              }
              static void App_TaskCreate (void) 
              { 
              OS_ERR os_err; 
              OSTaskCreate((OS_TCB *)&App_TaskMyADC8TCB, 
              (CPU_CHAR *)"MyADC8",
              (OS_TASK_PTR )App_TaskMyADC8, 
              (void *)0, 
              (OS_PRIO )APP_CFG_TASK_MyADC8_PRIO, 
              (CPU_STK *)&App_TaskMyADC8Stk[0], 
              (CPU_STK_SIZE )APP_CFG_TASK_MyADC8_STK_SIZE_LIMIT, 
              (CPU_STK_SIZE )APP_CFG_TASK_MyADC8_STK_SIZE, 
              (OS_MSG_QTY )0, 
              (OS_TICK )0, 
              (void *)0, 
              (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), 
              (OS_ERR 
              *)&os_err); 
              } 
              static void App_ObjCreate (void) 
              { 
              OS_ERR err; 
              OSSemCreate(&sem_sw2,"sem_sw2",0,&err); 
              OSSemCreate(&sem_sw3,"sem_sw3",0,&err); 
              OSMutexCreate(&mutex_LCD, "mutex_LCD", &err); 
              } 
              static CPU_INT16U SAR_ADC12_GetResult (void) 
              { 
              CPU_INT16U adcCount; 
              // 保持ADC计数 
              CPU_INT16U mVolts; 
              // 保持电压值 
              CPU_INT08U sampleCount; // 统计从ADC采集的样本数 
              CPU_INT32U voltSamples; // 保存累积样本 
              /* Perform eight consecutive conversions and get the average value 
              */ 
              voltSamples = 0; 
              for(sampleCount=0; sampleCount 
              /* Read ADC count and convert to milli volts */ 
              ADC_SAR_0_IsEndConversion(ADC_SAR_0_WAIT_FOR_RESULT); 
              adcCount = ADC_SAR_0_GetResult16(); 
              mVolts = ADC_SAR_0_CountsTo_mVolts(adcCount);
              /* Add the current ADC reading to the cumulated samples */ 
              voltSamples += mVolts; 
              } 
              mVolts = voltSamples/MAX_SAMPLE; 
              return mVolts; 
              } 
              static CPU_INT16U My_SAR_ADC_GetResult (CPU_INT08U range) 
              { 
              CPU_INT16U adcCount; 
              // 保持ADC计数 
              CPU_INT16S voltDigs[2];
               /* 中保留有效数字 */ 
              char str[20]; 
              CPU_INT08U i; 
              CPU_INT08U DAC8_val; 
              // VDAC8 的值 
              CPU_INT08U comp_1_out; 
              // 比较器输出 
              CPU_INT16U voltCount; 
              // 保持ADC的计数 
              CPU_INT16U mVolts; 
              //将ADC计数转换的结果保留为毫伏 
              CPU_INT08U sampleCount; 
              // 统计从ADC采集的样本数 
              CPU_INT32U voltSamples; 
              // 保持逐次样本 
              CPU_INT08U chan; 
              CPU_INT16S dc_offset; 
              // 偏移误差 
              CPU_FP32 
              dc_gain_cal_factor; // 增益误差 
              Sample_Hold_1_Start(); 
              Clock_1_Start(); 
              VDAC8_1_Start(); 
              PGA_1_Start(); 
              PGA_2_Start(); 
              Comp_1_Start(); 
              switch(range) 
              { 
              default: 
              case RANGE_2000MV: 
              PGA_1_SetGain(PGA_1_GAIN_01); 
              PGA_2_SetGain(PGA_2_GAIN_01); 
              dc_offset = DC_OFFSET_MV_2000MV; 
              dc_gain_cal_factor = DC_GAIN_CAL_FACTOR_2000MV; 
              break;
              case RANGE_200MV: 
              PGA_1_SetGain(PGA_1_GAIN_04); 
              PGA_2_SetGain(PGA_2_GAIN_02); 
              dc_offset = DC_OFFSET_100uV_200MV *Vin_GAIN_200MV/10; 
              dc_gain_cal_factor = DC_GAIN_CAL_FACTOR_200MV; 
              break; 
              case RANGE_20MV: 
              PGA_1_SetGain(PGA_1_GAIN_48); 
              PGA_2_SetGain(PGA_2_GAIN_02); 
              dc_offset = DC_OFFSET_10uV_20MV *Vin_GAIN_20MV/100; 
              dc_gain_cal_factor = DC_GAIN_CAL_FACTOR_20MV; 
              break; 
              } 
              /* Perform eight consecutive conversions and get the average value */ 	
              voltSamples = 0;//逐次样本数 为0 
              for(sampleCount=0; sampleCount 
              /* 开始新的采样*/ 
              SH_Control_Write(1); 
              CyDelayUs(1); 
              // 需要时间1us 
              /* 在保持期间完成一个转换*/ 
              voltCount = 0x00;//保持ADC的计数=0 
              for(i=0; i 
              DAC8_val = voltCount + (0x80  i);
              //VDAC8 的值 = 采样值+(10000000>i) 
              VDAC8_1_SetValue(DAC8_val);
              //设置采样比较值 
              CyDelayUs(1); 
              // VDAC8 settling time 
              comp_1_out = (Comp_1_GetCompare() != 0);//大于则输出1 
              voltCount += comp_1_out = TRACE_LEVEL_INFO) ? 									(void)(APP_TRACE x) : (void)0) 
              #define APP_TRACE_DEBUG(x) ((APP_TRACE_LEVEL >= TRACE_LEVEL_DEBUG) ? 									(void)(APP_TRACE x) : (void)0) 
              #endif 
              
              ISR.c
              CY_ISR(isr_sw2_Interrupt) 
              { 
              #ifdef isr_sw2_INTERRUPT_INTERRUPT_CALLBACK 
              isr_sw2_Interrupt_InterruptCallback(); 
              #endif /* isr_sw2_INTERRUPT_INTERRUPT_CALLBACK */ 
              /* Place your Interrupt code here. */ 
              /* `#START isr_sw2_Interrupt` */ 
              OS_ERR os_err; 
              CPU_SR_ALLOC(); 
              CPU_CRITICAL_ENTER(); 
              OSIntNestingCtr++; 
              /*通知μC/OS-III 进入中断*/ 
              CPU_CRITICAL_EXIT(); 
              OSSemPost(&sem_sw2, OS_OPT_POST_1, &os_err); 
              OSIntExit(); 
              /*通知μC/OS-III 退 出中断*/ 
              }
              

              7 测试与分析

              8位分辨率ADC下的2V量程和12位分辨率ADC下的固定2V量程的测量结果:

              【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验

              8位分辨率ADC下的200mV量程和12位分辨率ADC下的固定2V量程的测量结果:

              【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验

              8位分辨率ADC下的20mV量程和12位分辨率ADC下的固定2V量程的测量结果:

              【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验

              8 结论与问题讨论

              问题1:ADC采样精度不够高,导致测量结果不准确。

              解决方案:可以通过增加采样次数并进行平均,或者对ADC进行校准和调整来提高采样精度。

              问题2:SAR ADC的采样速度不够快,导致测量延迟较大。

              解决方案:可以通过优化ADC采样的时钟频率和采样触发方式,或者使用DMA(直接存储器访问)来提高采样速度和降低延迟。


免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,人围观)

还没有评论,来说两句吧...

目录[+]