前言
- 目前在学习AutoSar的通信模块,根据4.4.0的文档逐一实现通信。
- 底层是基于STM32固件库的Can通信模块,在他之上进行CAN、CanIf、PduR等模块的功能实现。
- 此博文不做过多的讲解,只贴代码,代码上会有官方文档的需求号和我的一些理解注释。
- 每一个模块我都是按照AutoSar官方文档需求去实现每一个功能,但是我也知道我水平所限,有些需求我暂时无法理解,我就没有去实现,望见谅。
- 具体模块的分析,希望读者自行参考文档、百度等途径。
本章说明
- 本章是做一些前提工作,主要是基本模块的说明等;
- 项目的搭建可以参考我另一篇文章搭建项目工程;
- 我贴出的代码,主要是和本次实验相关的,其他的一些无关代码,读者自行忽略,我就不做删除;
目录结构
公共代码
BswM模块
BSWM模块设计主要是为往后BSW模块做其他操作,比如初始化等。
//----------------------------------------------BswM.h
#ifndef BSWM_H
#define BSWM_H
#include "CanIf.h"
void BswM_Init();
#endif
//----------------------------------------------BswM.c
#include "BswM.h"
void BswM_Init(){
//CANIF模块初始化
CanIf_Init(NULL_PTR);
//TODO还需要其他模块的初始化
//开启控制器-理论上这里不能开启,我是为了测试用的
CanIf_SetControllerMode(Can_CanController_ECAN , CANIF_CS_STARTED);
}
EcuM模块
本模块的设计主要是对MACL模块的初始化工作
//----------------------------------------------EcuM.h
/*
[1]:EcuM在这里主要做的是处理整块Ecu需要初始化等一系列动作的开始
*/
#ifndef ECUM_H
#define ECUM_H
#include "EcuM_Cfg.h"
#define ECUM_EXTERNAL_DRIVER_INIT_ZERO Ecu_External_Driver_Init_Zero
/*
外设的初始化
目前:Port Spi CAN
待完善:IIC ADC FLASH(SPI) EEPROM(IIC) PWM WDG
*/
extern void EcuM_Init();
#endif
//----------------------------------------------EcuM_Cfg.h
#ifndef ECUM_CFG_H
#define ECUM_CFG_H
#include "TIM.h"
#include "Port.h"
#include "SPI.h"
#include "CAN.h"
#include "CanIf.h"
#include "Irq.h"
#include "CanIf.h"
void Ecu_External_Driver_Init_Zero();
#endif
//----------------------------------------------EcuM.c
#include "EcuM.h"
#include "CanIf.h"
void EcuM_Init(){
//TODO:做其他的处理
//外设初始化
Ecu_External_Driver_Init_Zero();
}
//----------------------------------------------EcuM_Cfg.c
#include "EcuM_Cfg.h"
void Ecu_External_Driver_Init_Zero(){
//Port初始化
Port_Init();
//IIC初始化
//SPI初始化
Spi_Init();
/*
The ECU State Manager module shall initialize the Can module
during startup phase by calling the function Can_Init before
using any other functions of the Can module.
*/
Can_Init(NULL_PTR);
//中断外设主函数
IRQ_Init();
//系统定时器初始化
System_TIM_Init();
}
Base模块
本模块主要是在CAN实现过程中定义的一些公共数据
//----------------------------------------------ComStack.h
#ifndef COM_STACK_CFG_H
#define COM_STACK_CFG_H
/**
* @brief This type serve as a unique identifier of a PDU within a software module.
* Allowed ranges: uint8 .. uint16
* @implements PduIdType_type
*/
typedef uint16_t PduIdType;
/**
* @brief This type serve as length information of a PDU in bytes.
* Allowed ranges: uint8 .. uint32
* @implements PduLengthType_Type
*/
typedef uint32_t PduLengthType;
#endif
//----------------------------------------------ComStack_Types.h
#ifndef COM_STACK_TYPES_H
#define COM_STACK_TYPES_H
#include "ComStack_Cfg.h"
typedef struct {
uint8_t* SduDataPtr;
PduLengthType SduLength;
} PduInfoType;
typedef enum {
TP_DATACONF,
TP_DATARETRY,
TP_CONFPENDING,
TP_NORETRY,
} TpDataStateType;
typedef struct {
TpDataStateType TpDataState;
PduLengthType TxTpDataCnt;
} RetryInfoType;
typedef enum {
BUFREQ_OK=0,
BUFREQ_NOT_OK=1,
BUFREQ_BUSY=2,
BUFREQ_OVFL=3,
} BufReq_ReturnType;
#endif
//----------------------------------------------Std_Types.h
#ifndef STD_TYPES
#define STD_TYPES
#include "stm32f10x.h"
/**
* @brief Success return code
*/
#define E_OK 0x00u
/**
* @brief Return code for failure/error.
*/
#define E_NOT_OK 0x01u
/**
* @brief ON State.
*/
#define STD_ON 0x01u
/**
* @brief OFF state.
*/
#define STD_OFF 0x00u
/**
* @brief The compiler abstraction shall provide the NULL_PTR define with a void pointer
* to zero definition.
*/
#define NULL_PTR ((void *)0)
#ifndef TRUE
#define TRUE (1u)
#endif
#ifndef FALSE
#define FALSE (0u)
#endif
typedef uint8_t Std_ReturnType;
typedef unsigned char boolean;
typedef struct{
uint16_t vendorID;
uint16_t moduleID;
uint8_t sw_major_version;
uint8_t sw_minor_version;
uint8_t sw_patch_version;
}Std_VersionInfoType;
#endif
IrqM模块
本模块为中断模块
//----------------------------------------------Irq.h
#ifndef IRQ_H
#define IRQ_H
#include "stm32f10x.h"
//------------中断分组
#define NVIC_IRQ_PRIORITY_GROUP NVIC_PriorityGroup_1
//------------CAN1控制器的FIFO0接收中断
#define NVIC_IRQ_CHANNEL_CAN_RX0_FUNCTION USB_LP_CAN1_RX0_IRQn
#define NVIC_IRQ_CHANNEL_CAN_RX0_PRE 1
#define NVIC_IRO_CHANNEL_CAN_RX0_SUB 0
//------------CAN1控制器的FIFO1接收中断
#define NVIC_IRQ_CHANNEL_CAN_RX1_FUNCTION CAN1_RX1_IRQn
#define NVIC_IRQ_CHANNEL_CAN_RX1_PRE 1
#define NVIC_IRO_CHANNEL_CAN_RX1_SUB 0
//------------TIM2通用定时器中断
#define NVIC_IRQ_CHANNEL_TIM_COS_FUNCTION TIM2_IRQn
#define NVIC_IRQ_CHANNEL_TIM_COS_PRE 0
#define NVIC_IRQ_CHANNEL_TIM_COS_SUB 0
extern void IRQ_Init();
#endif
//----------------------------------------------Irq.c
#include "Irq.h"
/**
STM32存在抢占优先级和响应(子)优先级
1:抢占优先级高的会抢占优先级低的,如果抢占优先级相同则看子优先级。
中断1:抢占-1,响应-2
中断2:抢占-2,响应-1
中断3:抢占-1,响应-3
顺序:中断1>中断3>中断2
2:中断顺序
设置中断分组
设置中断的抢占优先级和响应优先级
开启中断
*/
static void IRQ_CAN_Controller_One_Rx0_Init(){
NVIC_InitTypeDef CAN_Controller_One_Rx;
CAN_Controller_One_Rx.NVIC_IRQChannel = NVIC_IRQ_CHANNEL_CAN_RX0_FUNCTION;
CAN_Controller_One_Rx.NVIC_IRQChannelPreemptionPriority = NVIC_IRQ_CHANNEL_CAN_RX0_PRE;
CAN_Controller_One_Rx.NVIC_IRQChannelSubPriority = NVIC_IRO_CHANNEL_CAN_RX0_SUB;
CAN_Controller_One_Rx.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&CAN_Controller_One_Rx);
}
static void IRQ_CAN_Controller_One_Rx1_Init(){
NVIC_InitTypeDef CAN_Controller_One_Rx;
CAN_Controller_One_Rx.NVIC_IRQChannel = NVIC_IRQ_CHANNEL_CAN_RX1_FUNCTION;
CAN_Controller_One_Rx.NVIC_IRQChannelPreemptionPriority = NVIC_IRQ_CHANNEL_CAN_RX1_PRE;
CAN_Controller_One_Rx.NVIC_IRQChannelSubPriority = NVIC_IRO_CHANNEL_CAN_RX1_SUB;
CAN_Controller_One_Rx.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&CAN_Controller_One_Rx);
}
static void IRQ_TIM_System_COS_Init(){
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = NVIC_IRQ_CHANNEL_TIM_COS_FUNCTION;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_IRQ_CHANNEL_TIM_COS_PRE;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_IRQ_CHANNEL_TIM_COS_SUB;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void IRQ_Init(){
//中断优先级分组,设置抢占1 ,响应3
NVIC_PriorityGroupConfig(NVIC_IRQ_PRIORITY_GROUP);
//CAN1控制器接收中断初始化
IRQ_CAN_Controller_One_Rx0_Init();
IRQ_CAN_Controller_One_Rx1_Init();
//TIM2系统定时器中断初始化
IRQ_TIM_System_COS_Init();
}
Port模块
本模块设计为初始化用到的端口
注意:里面端口的定义我是根据我MCU的型号定义的,自行定义的时候,请根据实际情况声明定义。
//----------------------------------------------Port.h
#ifndef PORT_H
#define PORT_H
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "Port_PBCfg.h"
#define CAN_PORT_INIT() Can_Port_Init()
#define LED_PORT_INIT() Led_Port_Init()
#define SPI_PORT_INIT() Spi_Port_Init()
#define EEPROT_IIC_PORT_INIT() EEPROM_I2c_Port_Init()
//led端口初始化
void Led_Port_Init();
//SPI端口初始化
void Spi_Port_Init();
//EEPRON端口初始化
void EEPROM_I2c_Port_Init();
//can端口初始化
void Can_Port_Init();
void Port_Init();
#endif
//----------------------------------------------Port_PBCfg.h
#ifndef PORT_PBCFG_H
#define PORT_PBCFG_H
//-------------LED PORT--------------
#define LED_PORT GPIOB
#define LED_PORT_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED_PORT_FLICK_PIN GPIO_Pin_5
//-------------SPI PORT--------------
//-------------IIC PORT--------------
#define EEPROM_IIC_PORT GPIOB
#define EEPROM_IIC_GPIO_CLK RCC_APB2Periph_GPIOB
#define EEPROM_IIC_SCL_PIN GPIO_Pin_6
#define EEPROM_IIC_SDA_PIN GPIO_Pin_7
//-------------CAN PORT--------------
#define CAN_ECAN_PORT GPIOA
#define CAN_ECAN_GPIO_CLK RCC_APB2Periph_GPIOA
#define CAN_ECAN_PORT_RX_PIN GPIO_Pin_11
#define CAN_ECAN_PORT_TX_PIN GPIO_Pin_12
#endif
//----------------------------------------------Port.c
#include "Port.h"
/*
LED闪烁
时钟是在APB2
Port是GPIOB
TX是GPIO_Pin_5
*/
static void Led_Port_Init(){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(LED_PORT_GPIO_CLK , ENABLE);
GPIO_InitStructure.GPIO_Pin = LED_PORT_FLICK_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LED_PORT , &GPIO_InitStructure);
GPIO_SetBits(LED_PORT , LED_PORT_FLICK_PIN);
}
/*
SPI用到了端口复用
*/
static void Spi_Port_Init(){
}
static void EEPROM_I2c_Port_Init(){
RCC_APB2PeriphClockCmd(EEPROM_IIC_GPIO_CLK , ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//I/O口驱动电路的响应速度
GPIO_InitStructure.GPIO_Pin = EEPROM_IIC_SCL_PIN | EEPROM_IIC_SDA_PIN;
GPIO_Init(EEPROM_IIC_PORT , &GPIO_InitStructure);
//两个都拉高,这样可以处以空闲状态
GPIO_SetBits(EEPROM_IIC_PORT , EEPROM_IIC_SCL_PIN | EEPROM_IIC_SDA_PIN);
}
/*
时钟是在APB2
Port是GPIOA
TX是GPIO_Pin_12
RX是GPIO_Pin_11
*/
static void Can_Port_Init(){
RCC_APB2PeriphClockCmd(CAN_ECAN_GPIO_CLK , ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = CAN_ECAN_PORT_RX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(CAN_ECAN_PORT , &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = CAN_ECAN_PORT_TX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(CAN_ECAN_PORT , &GPIO_InitStructure);
}
void Port_Init(){
//LED端口初始化
LED_PORT_INIT();
//SPI端口初始化
SPI_PORT_INIT();
//EEPROM使用的I2c端口初始化
EEPROT_IIC_PORT_INIT();
//can端口初始化
CAN_PORT_INIT();
}
TIM模块
本模块为定时模块,在本次实验中,我是利用STM32通用TIM2产生1ms的中断,来完成任务的切换。
//----------------------------------------------TIM.h
#ifndef TIM_H
#define TIM_H
#include "stm32f10x.h"
#include "BSPCOS.h"
#define OS_TIM TIM2
#define OS_TIM_CLK RCC_APB1Periph_TIM2
#define OS_TIM_IT_TYPE TIM_IT_Update
void System_TIM_Init();
#endif
//----------------------------------------------TIM.c
#include "TIM.h"
void System_TIM_Init(){
//启动时钟
RCC_APB1PeriphClockCmd(OS_TIM_CLK , ENABLE);
//初始化定时器 产生1ms秒的计数
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_InitStructure.TIM_Prescaler = 7199; /* 定时器预分频,这个预分频是要和计数周期一起计算使用 */
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; /* 计数方式,向下计数 */
TIM_InitStructure.TIM_Period = 9; /* 计数周期 */
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; /* 时钟分频,意思是TIM2本来是72MHZ的,需不需要分频 */
TIM_TimeBaseInit(OS_TIM , &TIM_InitStructure);
//设置允许中断
TIM_ITConfig(OS_TIM , OS_TIM_IT_TYPE , ENABLE);
//使能TIM
TIM_Cmd(OS_TIM , ENABLE);
}
void TIM2_IRQHandler(void) //TIM2中断
{
if (TIM_GetITStatus(OS_TIM, OS_TIM_IT_TYPE) != RESET){
CosTimItChangeSystemTime(); /* 调用系统定时时间函数 */
TIM_ClearITPendingBit(TIM2, TIM_IT_Update );
}
}
timer_task模块
本模块为定时任务的切换模块
//----------------------------------------------BSPCOS.h
#ifndef BSPCOS_H
#define BSPCOS_H
#include "stm32f10x.h"
#include "BSPCOSCfg.h"
void CosInit();
/*
设置COS任务
*/
void SetCosTask(uint8_t priority , void(*fnct)(void*) , void *arg);
/*
启动COS任务
*/
void CosStart(uint8_t priority , uint32_t tenths);
/*
系统定时器中断调用的函数
*/
void CosTimItChangeSystemTime();
/*
负责检查个任务是否启动,并执行相关函数
*/
void CosTask();
#endif
//----------------------------------------------BSPCOSCfg.h
#ifndef BSPCOSCFG_H
#define BSPCOSCFG_H
//设置任务的总数
#define COS_MAX_NUM 3
//设置任务的优先级
#define COS_PRIORITY_TIMER2MS 0
#define COS_PRIORITY_TIMER4MS 1
#define COS_PRIORITY_TIMER10MS 2
//任务的运行使能
#define COS_ENABLE 1
#define COS_DIS_ENABLE 0
//任务的准备使能
#define COS_STATE_ENABLE 1
#define COS_STATE_DIS_ENABLE 0
//系统最大的时间
#define COS_MAX_USEABLE 0xFFFFFFF0
typedef struct{
uint8_t CosEn; //任务使能标志
uint8_t CosRdy; //任务状态标志
uint32_t CosCtr; //计数器,也就是延迟执行的计数,是在系统时间的基础上操作比较的
void (*CosFnct)(void*); //执行的任务
void *CosFnctArg; //任务的参数
}t_Cos;
#endif
//----------------------------------------------BSPCOSDef.h
#ifndef BSPCOSDEF_H
#define BSPCOSDEF_H
#include "BSPCOS.h"
#include "SEGGER_RTT.h"
/*
初始化系统的所有任务
*/
void InitCosAll();
/*
驱动2ms的定时任务
*/
void Timer2ms(void* p);
/*
驱动4ms的定时任务
*/
void Timer4ms(void* p);
/*
驱动10ms的定时任务
*/
void Timer10ms(void*p);
#endif
//----------------------------------------------BSPTimeTask.h
#ifndef BSPTIMETASK_H
#define BSPTIMETASK_H
void Task2ms();
void Task1000msBy4ms();
#endif
//----------------------------------------------BSPCOS.c
#include "BSPCOS.h"
static t_Cos sCosTbl[COS_MAX_NUM];
//这个是在中断中累加的,这个可以理解为系统时间,用这个时间去调控所有的任务
uint32_t sCosTimer = 0;
void CosInit(){
uint8_t index = 0;
t_Cos* pCos;
sCosTimer = 0;
pCos = sCosTbl;
for(; index < COS_MAX_NUM ; ++index){
pCos->CosEn = COS_DIS_ENABLE;
pCos->CosCtr = 0xFFFFFFFF;
pCos->CosRdy = COS_STATE_DIS_ENABLE;
++pCos;
}
}
void SetCosTask(uint8_t priority , void(*fnct)(void*) , void *arg){
t_Cos* pCos;
if(priority < COS_MAX_NUM){
pCos = (sCosTbl + priority);
pCos->CosFnct = fnct;
pCos->CosFnctArg = arg;
}
}
void CosStart(uint8_t priority , uint32_t tenths){
t_Cos* pCos;
if(priority < COS_MAX_NUM){
pCos = (sCosTbl + priority);
pCos->CosEn = COS_ENABLE; //在这里任务都使能了
pCos->CosCtr = tenths + sCosTimer;
if(tenths == 0){
pCos->CosRdy = COS_STATE_ENABLE;
}else{
pCos->CosRdy = COS_STATE_DIS_ENABLE;
}
}
}
void CosTimItChangeSystemTime(){
//定时器中断函数中,累加这个
++sCosTimer;
t_Cos* pCos;
//此处需要处理系统时间溢出的情况和延迟计数的溢出,
if(sCosTimer > COS_MAX_USEABLE){
for(uint8_t index = 0 ; index < COS_MAX_NUM ; ++index){
pCos = (sCosTbl + index);
if(pCos->CosCtr != 0xFFFFFFFF && pCos->CosCtr > COS_MAX_USEABLE){
pCos->CosCtr -= COS_MAX_USEABLE;
}
}
sCosTimer -= COS_MAX_USEABLE;
}
//此处判断任务是否执行
for(uint8_t index = 0 ; index < COS_MAX_NUM ; ++index){
pCos = (sCosTbl + index);
if(COS_ENABLE == pCos->CosEn && pCos->CosCtr <= sCosTimer){
pCos->CosRdy = COS_STATE_ENABLE;//任务如果是使能的情况下,并且任务的计数时间<=系统计数,那么任务状态开启
}
}
}
void CosTask(){
t_Cos* pCos;
void (*pfnct)(void*); //执行的函数
void* parg; //函数的参数
for(uint8_t index = 0 ; index < COS_MAX_NUM ; ++index){
pCos = (sCosTbl + index);
if(pCos->CosEn == COS_ENABLE && pCos->CosRdy == COS_STATE_ENABLE){
pfnct = pCos->CosFnct;
parg = pCos->CosFnctArg;
pCos->CosCtr = 0xFFFFFFFF;//这里把任务延时加到最大,这个数将在下一次任务启动中重新赋值
pCos->CosRdy = COS_STATE_DIS_ENABLE;//该任务将关闭执行,等待中断中在此开启
pCos->CosEn = COS_DIS_ENABLE;//关闭任务的使能,将在任务启动函数中,在此开启
//判断函数是不是为空
if(pfnct != (void (*)(void *))0){
(*pfnct)(parg);//执行函数
}
//其实我觉得这个只是为了保险,或者有些任务他只执行一次
if(pCos->CosCtr != 0xFFFFFFFF){
pCos->CosEn = COS_ENABLE;
}
return;//一次只执行一个任务
}
}
}
//----------------------------------------------BSPCOSDef.c
#include "BSPCOSDef.h"
#include "BSPTimeTask.h"
extern uint32_t sCosTimer;
extern void CAN_Test_1();
void InitCosAll(){
//先初始化COS
CosInit();
//开始设置任务
SetCosTask(COS_PRIORITY_TIMER2MS , Timer2ms , (void*)0);
SetCosTask(COS_PRIORITY_TIMER4MS , Timer4ms , (void*)0);
SetCosTask(COS_PRIORITY_TIMER10MS , Timer10ms , (void*)0);
//开始启动任务
CosStart(COS_PRIORITY_TIMER2MS, 0);//这个的函数将不会延迟,而是系统启动之后立马执行
CosStart(COS_PRIORITY_TIMER4MS, 1);
CosStart(COS_PRIORITY_TIMER10MS, 2);
}
/*
测试的时候,都改成按秒定时
*/
void Timer2ms(void* p){
CosStart(COS_PRIORITY_TIMER2MS, 2);
//后面就开始添加自己的函数
//SEGGER_RTT_printf(0,"time:%d task1 running...\n",sCosTimer);
Task2ms();
}
void Timer4ms(void* p){
CosStart(COS_PRIORITY_TIMER4MS, 4);
//后面就开始添加自己的函数
//SEGGER_RTT_printf(0,"time:%d task2 running...\n",sCosTimer);
}
void Timer10ms(void* p){
CosStart(COS_PRIORITY_TIMER10MS, 10);
//后面就开始添加自己的函数
//SEGGER_RTT_printf(0,"time:%d task3 running...\n",sCosTimer);
static uint32_t Global_Time_10_ms = 0;
if(!(Global_Time_10_ms % 100)){
Task1000msBy4ms();
}
if(Global_Time_10_ms == 100) Global_Time_10_ms = 0;
++Global_Time_10_ms;
}
//----------------------------------------------BSPTimeTask.c
#include "BSPTimeTask.h"
#include "CAN.h"
#include "CanIf.h"
extern void CanIf_Test1_by_2_ms();
void Task2ms(){
/* Can Main Function */
Can_MainFunction();
static uint8_t pduSet = 1;
if(pduSet){
CanIf_SetPduMode(Can_CanController_ECAN , CANIF_SET_ONLINE);
pduSet = 0;
}
CanIf_Test1_by_2_ms();
}
void Task1000msBy4ms(){
/* LED Flicker */
GPIO_WriteBit(GPIOB , GPIO_Pin_5 , (BitAction)(SET - GPIO_ReadOutputDataBit(GPIOB , GPIO_Pin_5)));
//CAN_Test_1();
}
main
主函数
//----------------------------------------------main.c
#include "stm32f10x.h"
#include "EcuM.h"
#include "BswM.h"
#include "BSPCOS.h"
int main(void){
//delayInit();
//ECU初始化
EcuM_Init();
//BSW初始化
BswM_Init();
//初始化系统的所有定时任务
InitCosAll();
while(1){
CosTask();
}
return 0;
}