学习笔记(三)

提示:小菜鸟的学习路


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、LCD画幅频曲线

AD9854扫频通过待测电路,后接一个有效值检测模块通过该模块将扫频频率对应的幅值保存下来,存放在一个数组里,根据数值里的值进行画图。

for(n=0;n<280-1;n++)
	    {
			  adcx = ADC_GetSampleFliter(ADC_Channel_5, 400, 80);
			  vol = adcx * 3300 / 4095;
			  printf("vol= %d\r\n",vol);
              Draw[n] = (u16)(u16)(vol * 1.0373f - 161.72f);
	   	}
		 for(n = 0; n < 280 - 1; n++)
     {
             Draw[n] = (u16)Draw[n] * 200 / 3300); 
			 printf("ADC_Draw= %f\r\n",Draw[n]);
     }
		 for(n = 1; n < 280 - 2; n++)
     {
 
      
       LCD_DrawLine((n + 20), 240 - (ADC_Draw[n] + 20),(n + 21),  240- (ADC_Draw[n + 1] + 20));							
      }

二、STM32嵌入FreeRTOS操作系统

//RTOS操作系统
#if 0
RTOS系统的核心就是任务管理。

在做裸机STM32,一般都是在main函数里面用while(1)做一个大循环来完成所有的处理
即应用程序是一个无限的循坏,循坏中调用相应的函数完成所需的处理。也会在中断中
完成一些处理----->单任务系统,也称为前后台系统。中断服务函数作为前台程序,大
循环while(1)作为后台程序。

#endif

#if 0
使用前后台系统的实时性差,前后台系统各个任务(应用程序)都是排队等着轮流执行,
不管你这个程序现在有多紧急,没轮到你就只能等着!就是说所有你调用的函数的优先
级都是一样的。
多任务系统会把这个问题解决。
多任务系统的运行:高优先级可以打断低优先级的运行而执行,这样就保证了那些紧急
任务的运行。
#endif
//任务的基础知识
/*
任务特性:
1.简单。 -------使用任务和编写任务简单
2.没有使用限制 ---------没有任务数量的限制,同一个优先级下可以有多个任务
3.支持抢占 ----------高优先级的任务可以抢占低优先级的任务的CPU的使用权
4.支持优先级 ---------每个任务都存在着优先级
5.每个任务都拥有堆栈导致了RAM使用量增大 ---------堆栈的含义是切换任务方便,RAM=内存
6.如果使用抢占的话的必须仔细的考虑重入的问题
四种任务状态:
1.运行态 ----当前任务处于运行的状态
2.就绪态 ----准备就绪要执行任务(告诉任务调度器可以运行任务了)
3.阻塞态 ----等某个事件没有发现的状态
4.挂起态 ----将任务暂定运行
*/
#if 0
first:
在使用RTOS的时候一个实时应用可以作为一个独立的任务。每个任务都有自己的运行环
境,不依赖于系统中其他任务或者RTOS调度器。
就比如说,在某个时间段执行任一函数,这个执行命令由RTOS调度器支配。
每个任务都要自己的堆栈,当执行任务时,会调用该任务的堆栈。
second:
任务优先级,优先级数字越低表示任务的优先级越低,0 的优先级最低。以此类推。
third:
任务的实现:
在使用RTOS的过程中,我们要使用函数xTASKCreate()和XTASKCreateStatic()来创建任务
这两个函数的第一参数pxTaskCode,就是这个任务的任务函数。
#endif

//任务实现
#if 0
FreeRTOS给出的任务模板:
void vATaskFunction(void *pvParameters) //任务函数本质也是函数,所以肯定有任务名什么的,不过这里要注意任务函数的返回值一定要为void类型,
{ //也就是无返回值,而且任务的参数也是void指针类型的!任务函数名可以根据实际情况来定义。
for(; 😉 //任务的具体执行过程也就是一个大循环,for(;;)就代表一个循坏,作用和while(1)一样。
{

        -任务应用程序-                      //循坏里面就是真正的代码任务了,此任务具体要干的活在这里实现。
        vTaskDelay();                       //FreeRTOS的延时函数,此处不一定要用延时函数,其他只要能让FreeRTOS发生任务切换的API函数都可以
                                            //比如请求信号量、队列等,甚至直接调用任务调用器。
    }
    /*不能从任务函数中返回或者退出,从任务函数中返回或退出的话就会调用
    configASSERT(),前提是你定义了configASSERT()。如果一定要从任务函数中
    退出的话一定要调用函数vTaskDelete(NULL)来删除此任务*/
    
    vTaskDelete(NULL);                     //任务函数一般不允许跳出循坏,如果一定要跳出循坏的话一定要调用函数vTaskDelete(NULL)删除任务。
    
}

#endif

//任务控制块
#if 0

FreeRTOS把任务属性定义成一个结构体:TCB_t;在使用函数xTaskCreate()创建任务时候就自动给每个任务分配一个任务控制块。
typedef struct tskTaskControlBlock
{
volatile StackType_t *pxTopOfStack; //任务堆栈栈顶
ListItem_t xStateListItem; //任务列表项
ListItem_t xEventListItem; //事件列表项
UBaseType_t uxPriority; //任务优先级
StackType_t *pxStack; //任务堆栈起始地址
char pcTaskName[configMAX_TASK_NAME_LEN]; //任务名字
}tskTCB;

#endif

//任务的创建和删除
#if 0
任务创建和删除的本质就是调用FreeRTOS的API函数。

xTaskCreate() 使用动态的方法创建一个任务。
用该函数创建任务的模板是:
BaseType_t XTaskCreate( TaskFunction pxTaskCode, //pxTaskCode:任务函数
const char const pcName,//pcName:任务名字
const uint16_t usStackDepth,//usStackDepth:任务堆栈的大小,实际要
4。
void *const pvParameters,//pvParameters:传递给任务函数的参数
UBaseType_t uxPriority,//uxPriority:任务优先级
TaskHandle_t *const pxCreatedTask,//pxCreatedTask:任务句柄,任务创建成功以后会返回任务的任务句柄。
)
XTaskCreateStatic() 使用静态的方法创建一个任务。
XTaskCreateRestricted() 创建一个使用MPU进行限制的任务,相关内存使用动态内存分配。
VTaskDelete() 删除一个任务

#endif
//for example
#if 0
任务创建的第一步是任务设置
模板如下:
#define START_TASK_PRIO 1 //任务优先级
#define START_STK_SIZE 128 //任务堆栈大小
TaskHandle_t StartTask_Handler; //任务句柄
void start_task(void pvParameters); //任务函数
任务创建的第二步是任务配置
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char
)“start_task”, //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度,RTOS开始运行
任务创建的第三步就是写任务函数的功能
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
–功能–
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
#endif

//RTOS队列
#if 0
在实际中,会遇到一个任务或者中断服务函数需要和另外一个任务进行“沟通交流”,这个“沟通交流”的过程就是消息传递的过程。
在没有操作系统的时候两个应用程序进行消息传递一般使用全局变量的方式,但是在全局变量中使用操作系统的应用中用全局变
量来传递消息就会涉及到“资源管理”的问题,所以要使用队列的机制来完成任务与任务、任务与中断之间的消息传递。

队列是为了任务与任务、任务与中断之间的通信而准备的,可以在任务与任务、任务与中断之间传递消息。

数据存储:队列采用先进先出(FIFO)的存储缓冲机制,也就是往队列发送数据的时候也称为入队永远都是发送到队列的尾部,而队列提取数据
的时候也称为出队是从队列的头部提取的。

队列不是属于某个特别指定的任务的,任何任务都可以向队列中发送消息,或者从队列中提出消息。
出队阻塞:当任务从一个队列中读取消息的时候可以指定一个阻塞时间,这个阻塞时间就是当任务从队列中读取消息无效的时候的时间。
入队阻塞:进入队列设置一个时间。
#endif

//队列结构体
#if 0
typedef struct QueueDefinition
{
int8_t *pcHead; //指向队列存储区开始地址
int8_t *pcTail; //指向队列存储区最后一个字节
int8_t *pcWriteTo; //指向存储区中下一个空闲区域

union							
{
	int8_t *pcReadFrom;			//当用作队列的时候指向最后一个出列的队列项首地址
	UBaseType_t uxRecursiveCallCount;//当用作递归互斥量的时候用来记录递归互斥量被调用的次数
} u;

List_t xTasksWaitingToSend;		//等待发送任务列表,那些因为队列满导致入队失败而进入阻塞态的任务会挂到此列表上
List_t xTasksWaitingToReceive;	//等待接收任务列表,那些因为队列空导致出队失败而进入阻塞态的任务会挂到此列表上

volatile UBaseType_t uxMessagesWaiting;//队列中当前队列项数量吗,也就是消息数
UBaseType_t uxLength;			//创建队列时指定的队列长度,也就是队列中最大允许的队列项(消息)数量
UBaseType_t uxItemSize;			//创建队列时指定的每个队列项(消息)最大长度,单位字节

volatile int8_t cRxLock;		//当队列上锁以后用来统计从队列中接收到的队列项数量,也就是出队的队列项数量,当队列没有上锁的话此字段为queueUNCLOCKED
volatile int8_t cTxLock;		//当队列上锁以后用来统计从队列中发送到的队列项数量,也就是入队的队列项数量,当队列没有上锁的话此字段为queueUNCLOCKED

} xQUEUE;
#endif
//队列创建
#if 0
和任务的创建一样,有静态的和动态的。
队列的创建:
使用XQueueCreate();函数
此函数的本质是一个宏,用来创建动态队列,此宏最终调用的函数是xQueueGenericCreate(),函数原型:
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength,//uxQueueLength:要创建的队列的队列长度,这里是队列的项目数
UBaseType_t uxItemSize) //uxItemSize:队列中每个项目(消息)的长度,单位字节
xQueueGenericCreate()用来动态创建队列
QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength,//uxQueueLength:要创建的队列的队列长度,这里是队列的项目数
const UBaseType_t uxItemSize, //uxItemSize:队列中每个项目(消息)的长度,单位字节
const uint8_t ucQueueType) //ucQueueType:队列类型一共有六种
//入队函数
1.任务级入队函数
xQueueSend()/xQueueSendToBack() //发送消息到队列尾部(后向入队),这两个函数是一样的。
xQueueSendToFront() //发送消息到队列头(前向入队)
xQueueOverwrite() //发送消息到队列,带覆写功能,当队列满了以后自动覆盖掉旧的消息
2.中断级入队函数
xQueueSendFromISR()/xQueueSendToBackFromISR() //发送消息到队列尾(后向入队),这两个函数是一样的,用于中断服务函数
xQueueSendToFrontFromISR() //发送消息到队列头(前向入队),用于中断服务函数
xQueueOverwriteFromISR() //发送消息到队列,带覆写功能,当队列满了以后自动覆盖掉旧的消息,用于中断服务函数

/用户使用xQueueSend这是一个宏定义函数考系统函数xQueueGenericSend实现,用户不用设置该函数
xQueue—队列句柄指明要向哪个队列发送数据,创建队列成功以后会返回此队列的队列句柄 ;
pvItemToQueue—指要发送的消息,发送时候会将这个消息拷贝到队列中
xTicksToWait—阻塞时间
/
#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
/用户使用xQueueSendToBack这是一个宏定义函数考系统函数xQueueGenericSend实现,用户不用设置该函数
xQueue—队列句柄指明要向哪个队列发送数据,创建队列成功以后会返回此队列的队列句柄 ;
pvItemToQueue—指要发送的消息,发送时候会将这个消息拷贝到队列中
xTicksToWait—阻塞时间
/
#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
/用户使用xQueueSendToFront这是一个宏定义函数考系统函数xQueueGenericSend实现,用户不用设置该函数
xQueue—队列句柄指明要向哪个队列发送数据,创建队列成功以后会返回此队列的队列句柄 ;
pvItemToQueue—指要发送的消息,发送时候会将这个消息拷贝到队列中
xTicksToWait—阻塞时间
/
#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
/用户使用xQueueOverwrite这是一个宏定义函数考系统函数xQueueGenericSend实现,用户不用设置该函数
xQueue—队列句柄指明要向哪个队列发送数据,创建队列成功以后会返回此队列的队列句柄 ;
pvItemToQueue—指要发送的消息,发送时候会将这个消息拷贝到队列中
/
#define xQueueOverwrite( xQueue, pvItemToQueue ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE )

//出队函数
1.任务级出队函数
XQueueReceive() //从队列中读取队列项(消息),并且读取完以后删掉队列项(消息)
XQueuePeek() //从队列中读取队列项(消息),并且读取完以后不删掉队列项(消息)
2.中断级出队函数
xQueueReceiveFromISR() //从队列中读取队列项(消息),并且读取完以后删掉队列项(消息),用于中断服务函数
xQueueReceiveFromISR() //从队列中读取队列项(消息),并且读取完以后不删掉队列项(消息),用于中断服务函数
/用户使用xQueueReceive这是一个宏定义函数考系统函数xQueueGenericReceive实现,用户不用设置该函数
xQueue—队列句柄指明要向哪个队列发送数据,创建队列成功以后会返回此队列的队列句柄 ;
pvBuffer—保存数据的缓冲区,读取队列的过程中会将读取到的数据拷贝到缓冲区中
xTicksToWait–阻塞时间
/
#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )

#endif

//信号量
#if 0
信号量的主要目的有两个:共享资源访问和与任务同步。
信号量用于控制共享资源访问的场景相当于一个上锁机制,代码只有获得了这个锁的钥匙才能执行。

信号量用于任务同步:在执行中断服务函数的时候可以通过向任务发送信号量来通知任务它期待的事件发生了,当退出中断服务函数以后在任务调度器的
调度下同步的任务就会执行。
简单来说就是在触发中断时会产生一个信息量去执行任务。

#endif
//创建二值信号量
xSemaphoreCreateBinary(); //动态创建二值信号量
//释放信号量
xSemaporeGive() //任务级信号量释放函数
xSemaphoreGiveFromISR() //中断级信号量释放函数
//获取信号量
xSemaporeTake() //任务级信号量获取函数
xSemaphoreTakeFromISR() //中断级信号量获取函数

三、硬件电路–积分器

在这里插入图片描述
积分电路根据电路的时间常数和放大器的带宽输出某个频率范围上输入信号的积分。
图中Vos的作用:可调节的基准电压可以抵消输入的偏移电压。
理想的积分电路会根据输入偏移电压的极点在电源轨上饱和并需要添加一个反馈电阻R2,以提供稳定的直流运行点。
设计步骤:
1.将R1设置成标准值:100k
2.计算设置单位增益积分分频所需要的C1 :C1= 1/(2piR1f0dB)
3.计算将较低的截止频率设置为比最低工作频率10倍频所需要的R2:
R2>=10/(2
piC1fmin)
4.选择增益带宽至少为所需要的最大频率10倍的放大器。

结果: 输入 输出
正弦波 余弦波
三角波 正弦波
方波 三角波

总结

这周因为考虑到了多任务同时运行时的实时性,学习RTOS操作系统。
但自己的知识储备有限,导致自己学习的进度很慢,所以又返回前后台系统去学习基础知识,然后再去搞RTOS。
我很笨,我慢慢掌握。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值