📄 djyos.c
字号:
//----------------------------------------------------
//Copyright (C), 2004-2009, lst.
//版权所有 (C), 2004-2009, lst.
//所属模块:核心模块
//作者:lst
//版本:V1.0.0
//文件描述:事件类型、事件管理以及多事件调度相关的代码全在这里了。
//其他说明:
//修订历史:
// 2. ...
// 1. 日期:
// 作者:
// 新版本号:
// 修改说明:
//------------------------------------------------------
#include "inc_os.h"
#include "gpio.h"
#include <string.h>
struct process_vm *pg_my_process;
//为cn_events_limit条事件控制块分配内存
static struct event_script tg_event_table[cn_events_limit];
//为cn_evtts_limit个事件类型控制块分配内存
static struct event_type tg_evtt_table[cn_evtts_limit];
static struct event_script *pg_event_free; //空闲链表头,不排序
//轮转调度时间片,0表示禁止轮转调度,默认1,RRS = "round robin scheduling"缩写。
static uint32_t u32g_RRS_slice = 1;
struct event_script *pg_event_ready; //就绪队列头
struct event_script *pg_event_running; //当前正在执行的事件
static struct event_script *pg_event_delay; //闹钟同步队列表头
static uint32_t u32g_running_start; //当前运行中事件的开始执行时间.
static uint32_t u32g_os_ticks; //操作系统运行ticks数
volatile static uint32_t u32g_delay_10uS=40;
uint32_t u32g_ns_of_u32for; //for(i=j;i>0;i--);语句,i和j都是u32型,每循环纳秒数
uint32_t u32g_ns_of_u16for; //for(i=j;i>0;i--);语句,i和j都是u16型,每循环纳秒数
uint32_t u32g_ns_of_u8for; //for(i=j;i>0;i--);语句,i和j都是u8型,每循环纳秒数
//----设置指令延时常数---------------------------------------------------------
//功能: 设置指令延时常数,使y_delay_10us函数的延时常数=10uS.
// 调用此函数后,延时常数准确==10uS,不管用何种编译器和优化级别
// 44b0x打开cache的情况下,延时 u32g_delay_10uS 约49,误差约2%
//参数:无
//返回: 无
//备注: 本函数移植关键
//-----------------------------------------------------------------------------
void __y_set_delay(void)
{
uint32_t counter,u32_fors=64000,i;
uint16_t u16_fors=64000;
uint8_t u8_fors=250;
uint32_t u32_u8 = 128;
volatile uint32_t u32loops;
volatile uint16_t u16loops;
volatile uint8_t u8loops;
timer_set_clk_source(5,0); //timer5的时钟源=cn_timer_clk/2,最高时钟。
timer_set_precale(2,0); //预分频数为1(不预分频)
timer_set_type(5,1); //自动加载连续工作
timer_set_counter(5,(uint16_t)(2*cn_timer_clk/2000)); //2000uS,减计数
timer_reload(5);
timer_start(5);
do //测量32位变量循环时间(nS)
{
int_echo_line(cn_irq_line_timer5); //清中断标志
while( ! int_query_line(cn_irq_line_timer5));//直到发生中断,重新计数
for(u32loops=u32_fors;u32loops>0;u32loops--); //循环u32_fors次
counter = timer_read(5); //读取循环u32_fors次所需时间
u32_fors >>= 1; //u32_fors减半
}while(int_query_line(cn_irq_line_timer5));//中断已发生,说明u32_fors次循环
//大于2mS,u32_fors减半,再次循环,直到中断不发生
counter = 2*cn_timer_clk/2000 - counter; //取实际脉冲数。
u32g_ns_of_u32for = counter*2000/(2*cn_timer_clk/2000)*1000 /(u32_fors<<1);
do //测量16位变量循环时间(nS)
{
int_echo_line(cn_irq_line_timer5); //清中断标志
while( ! int_query_line(cn_irq_line_timer5));//直到发生中断,重新计数
for(u16loops=u16_fors;u16loops>0;u16loops--); //循环u16_fors次
counter = timer_read(3); //读取循环u32_fors次所需时间
u16_fors >>= 1; //u16_fors减半
}while(int_query_line(cn_irq_line_timer5));//中断已发生,说明u32_fors次循环
//大于2mS,u32_fors减半,再次循环,直到中断不发生
counter = 2*cn_timer_clk/2000 - counter; //取实际脉冲数。
u32g_ns_of_u16for = counter*2000/(2*cn_timer_clk/2000)*1000 /(u16_fors<<1);
do //测量8位变量循环时间(nS)
{
int_echo_line(cn_irq_line_timer5); //清中断标志
while( ! int_query_line(cn_irq_line_timer5));//直到发生中断,重新计数
for(i = (uint8_t)u32_u8; i > 0; i--)
for(u8loops=u8_fors;u8loops>0;u8loops--); //循环u8_fors次
counter = timer_read(3); //读取循环k次所需时间
u32_u8 >>= 1; //u32_u8减半
}while(int_query_line(cn_irq_line_timer5));//中断已发生,说明u32_fors次循环
//大于2mS,u32_fors减半,再次循环,直到中断不发生
counter = 2*cn_timer_clk/2000 - counter; //取实际脉冲数。
u32g_ns_of_u8for = counter*2000/(2*cn_timer_clk/2000)*1000
/((u8_fors+1) * (u32_u8<<1));
u32g_delay_10uS = 10000/u32g_ns_of_u32for;
}
//----10微秒级延时-------------------------------------------------------------
//功能:利用循环实现的微秒分辨率延时,调用__y_set_delay函数后才能使用本函数,
// 否则在不同优化级别和不同编译器下,延时数不同.
//参数:time,延时时间,单位为10微秒,最多655毫秒。
//返回:无
//注意:不建议使用此函数做太长延时,长延时请使用函数 y_timer_sync,
//-----------------------------------------------------------------------------
void y_delay_10us(volatile uint16_t time)
{
volatile uint32_t i;
for(; time > 0; time--)
for(i = u32g_delay_10uS; i >0 ; i--);
}
//----实时串长度---------------------------------------------------------------
//功能: strlen函数的执行时间不可控,不宜在实时环境中使用。
//参数: s,被测字符串
// over,最长检测长度,over=0则不限长度,与strlen函数无异。
//返回: 串长度,在over范围内没有检测到串结束则返回-1
//-----------------------------------------------------------------------------
sint32_t rtstrlen(const char *s,uint32_t over)
{
uint32_t len;
if(over == 0)
return strlen(s);
else
{
for(len = 0; len < over; len++)
{
if(s[len] =='\0')
{
return len;
break;
}
}
return cn_limit_uint32;
}
}
//----读取当前ticks-------------------------------------------------------------
//功能:读取操作系统时钟
// u32g_os_ticks 为32位无符号变量,ARM是32位机,可以直接读取,非32位系统中
// 读取 u32g_os_ticks 需要超过1个周期,因此访问SysTimer时需要关中断。
//参数:无
//返回:当前时钟
//-----------------------------------------------------------------------------
uint32_t y_get_time(void)
{
uint32_t time;
#if (32 > cn_cpu_bits)
//若处理器字长不是32位,需要多个周期才能读取os_ticks,该过程不能被时钟中断打断.
int_save_line(cn_irq_line_timer5);
#endif
time = u32g_os_ticks;
#if (32 > cn_cpu_bits)
//若处理器字长不是32位,需要多个周期才能读取os_ticks,该过程不能被时钟中断打断.
int_restore_line(cn_irq_line_timer5);
#endif
return time;
}
//----读取精密时间-----------------------------------------------------------
//功能:读取操作系统精密时钟,时间单位在配置文件中设置,依硬件不同而不同,一般设为
// tick的百分之一或者千分之一,44b0x中设为千分之一.结果是从上次ticks改变到
// 现在的时间间隔/
//参数:无
//返回:时间值
//备注: 本函数是移植关键函数.
//-----------------------------------------------------------------------------
uint32_t y_get_fine_time(void)
{
return 1000-pg_timer_reg->TCNTO5;
}
//以下为多任务管理函数
//----tick中断-----------------------------------------------------------------
//功能:为操作系统产生时钟源,并比较理闹钟同步队列中的事件,如果有闹铃时间到的
// 事件,就把他们激活的ready队列中。如果时间片轮转调度被允许,还要看是否要
// 执行轮转。ticks被设置为异步信号。
//参数:line,ticks中断的中断线号,实际上不用。
//返回:无
//-----------------------------------------------------------------------------
uint32_t __y_isr_tick(ufast_t line)
{
struct event_script *pl_ecb,*pl_ecbp,*pl_ecbn;
u32g_os_ticks++; //系统时钟,4294967296次后溢出,将环绕
if(pg_event_delay != NULL)
{
pl_ecb = pg_event_delay;
while(1)
{
if(pl_ecb->delay_end == u32g_os_ticks)
{
if(pl_ecb->sync_head != NULL) //事件在某同步队列中
{
if(*pl_ecb->sync_head == pl_ecb)//本事件是该同步队列的首事件
{
if(pl_ecb->multi_next == pl_ecb) //队列中只有一个事件
{
*pl_ecb->sync_head = NULL;
pl_ecb->multi_next = NULL;
pl_ecb->multi_previous = NULL;
}else //队列中有多个事件
{
//头指针指向下一个事件
*pl_ecb->sync_head = pl_ecb->multi_next;
pl_ecb->multi_previous->multi_next
= pl_ecb->multi_next;
pl_ecb->multi_next->multi_previous
= pl_ecb->multi_previous;
}
}else //本事件不是首事件
{
pl_ecb->multi_previous->multi_next
= pl_ecb->multi_next;
pl_ecb->multi_next->multi_previous
= pl_ecb->multi_previous;
}
pl_ecb->sync_head = NULL; //事件头指针置空
}
if(pl_ecb->next == pl_ecb) //这是闹钟同步队列最后一个结点.
{
pg_event_delay = NULL;
pl_ecb->last_status.all = pl_ecb->event_status.all;
pl_ecb->event_status.bit.event_delay = 0;
pl_ecb->event_status.bit.wait_overtime = 0;
__y_event_ready(pl_ecb);
break;
}else
{
pg_event_delay = pl_ecb->next;
pl_ecb->next->previous = pl_ecb->previous;
pl_ecb->previous->next = pl_ecb->next;
pl_ecb->last_status.all = pl_ecb->event_status.all;
pl_ecb->event_status.bit.event_delay = 0;
pl_ecb->event_status.bit.wait_overtime = 0;
__y_event_ready(pl_ecb);
pl_ecb = pg_event_delay;
}
}else
break;
}
}
pg_event_running->consumed_time++;
//下面处理时间片轮转调度.
//因在开异步信号(允许调度)才可能进入__y_isr_tick,即使因闹钟响导致新事件加入,
//也不影响pg_event_running是同优先级首事件的性质,但可能不等于pg_event_ready
if(u32g_RRS_slice != 0) //允许轮转调度
{
if( (pg_event_running->prio == pg_event_running->next->prio)
&&(pg_event_running != pg_event_running->next) )
{//该优先级有多个事件,看轮转时间是否到
if(pg_event_running->consumed_time%u32g_RRS_slice == 0) //时间片用完
{
//先处理首事件链表
pl_ecb = pg_event_running->next;
pl_ecbn = pg_event_running->multi_next;
pl_ecbp = pg_event_running->multi_previous;
if(pg_event_ready == pg_event_running)
pg_event_ready = pl_ecb;
pl_ecbp->multi_next = pl_ecb;
pl_ecb->multi_previous = pl_ecbp;
pl_ecbn->multi_previous = pl_ecb;
pl_ecb->multi_next = pl_ecbn;
pg_event_running->multi_next = NULL;
pg_event_running->multi_previous = NULL;
//再处理就绪链表
pl_ecbn = pg_event_ready->multi_next;
pl_ecbp = pg_event_running->previous;
pl_ecbp->next = pg_event_ready;
pg_event_ready->previous = pl_ecbp;
pg_event_running->previous = pl_ecbn->previous;
pg_event_running->next = pl_ecbn;
pl_ecbn->previous->next = pg_event_running;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -