本帖最后由 xld0932 于 2023-2-16 12:12 编辑
#申请原创# @21小跑堂
2022年随着新定义入住了21ic,幸运的参与了新定义在21ic的首次评测活动,基于NBK-RD8x3x作为核心底板结合了NBK-EBS001触控扩展板的硬件资源,让我开始去了解新定义,芯片功能、性能、选型、以及它的优势;后来在年末的时候,新定义官方又送了两块扩展板,作为新年礼物:分别是NBK-EBS002基础功能扩展板和NBK-EBS003 IOT扩展板;新定义不断的在丰富着自己的硬件平台、也在不断的完善了软件套件(易码魔盒),为的就是让使用新定义的开发者有更好的体感,能够更快的上手、不受限于芯片底层驱动、软件架构、硬件等等,你能想到的,新定义可能都在准备的进行中……让开发者将更多的精力投入在产品上……能够实现项目敏捷开发的同时,兼顾产品的功能和性能……
本文将详细介绍一下基于NBK-RD8x3x核心底板结合NBK-EBS002基础功能扩展板实现的全部功能测试,以及在调试过程中做过的一些尝试和使用心得,分享给大家;首先我们还是将提前准备的的资料罗列一下:
1、RD8T36P48J芯片数据手册
2、易码魔盒EasyCodeCube_RDSV3.2.5_20230105
3、新定义NBK-RD8x3x应用资料
上面3个都可以在新定义官网的下载中心进行下载:https://www.rdsmcu.com/
4、NBK-EBS002基础功能扩展板原理图:
NBK-EBS002原理图.pdf
(308.55 KB)
除了软件资料外,我们硬件平台也是不可缺少的:
1、NBK-RD8x3x核心底板
2、NBK-EBS002基础功能扩展板
3、RD LINK PRO
因为在NBK-RD8x3x核心底板上已经带有ISP下载功能模块,所以RD LINK PRO是可选择工具;ISP仅可以下载程序到MCU运行,通过实际的运行结果验证功能是否正常;而RD LINK PRO除了具有下载程序的功能之外,还带有脱机烧录、在线调试、仿真等等丰富的功能……各位小伙伴可以根据需要自行选择
细心的小伙伴可以看出,在每一个功能外设旁边都已经标有了使用了MCU的资源了,这样可以让我们在不看原理图的状态下,就可以知道原理设计,点赞哦
我们结合NBK-EBS002基础功能扩展板实现的软件功能如下:
1、自定义时间片任务管理、调度机制(链表实现)
2、GPIO输出控制LED、GPIO输入检测KEY输入状态
3、3路PWM输出控制RGB灯,根据人体视觉感观,控制RGB亮度调节、颜色切换
4、1路PWM控制蜂鸣器
5、通过芯片的LCD/LED外设功能驱动显示4位8段数码管
6、通过板载的可调节电阻实现ADC检测与显示、通过2个可调节电阻实现比较器的功能
7、NTC实时温度检测与显示
最后综合实现一个功能:
系统启动后,RGB自动进行亮度调节显示、颜色切换;通过按键切换工作模式,每按一次切换一个工作模式,对应的LED亮一次,蜂鸣器响一声、模式1为LCD数码管显示累加数值、模式2为数码管显示ADC采样数值、模式3为数码管显示NTC实时温度、模式4为比较器功能,将比较结果通过蜂鸣器的形式进行体现;
1、自己定义时间片任务管理、调度机制(链表实现)
在单片机中我接触到的有两种运行的形式,一个是带RTOS实时操作系统的,比如支持51MCU的RTX、还有老早之前接触过的叫SmallRTOS的;另外一个就是不带操作系统的,一般由前后台系统组成了MCU的整体运行和调用;我们为了方便项目功能的应用,都会有自己的一些规划,有依据状态机的、有依据时间片的……而下面讲到的就是我自己写的一个基于时间片的任务管理和调度机制;
任务调度建立在TIM0定时器,系统默认是使用的32MHz的系统运行频率,我们将TIM0的滴答时间设置到1ms,作为我们系统的基础时间;在TIM0定时器中断中去处理每个节点任务的运行间隔时间是否达到,如果达到则置位运行标志位,为了不在TIM0中断占用太多调用功能函数和处理的时间,我们在while(1)循环中通过判断运行标志位,去调用具体的功能函数;代码如下:
/***********************************************************************************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url] : D1->32000000Hz / 32000 = 1000Hz, 1ms D12->32000000Hz / 26666 = 100Hz, 10ms
* @param
* @retval
* @attention
*********************************************************************************************************************/
void TimeSliceInitTIM(void)
{
TIM0_DeInit();
TIM0_TimeBaseInit(TIM0_PRESSEL_FSYS_D1, TIM0_MODE_TIMER);
TIM0_WorkModeConfig(TIM0_WORK_MODE1, (65535 - 32000), 0);
TIM0_ITConfig(ENABLE, LOW);
TIM0_Cmd(ENABLE);
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void TIM0_IRQHandler(void) interrupt 1
{
TIM0_Mode1SetReloadCounter(65535 - 32000);
TIM0_Tick++;
TimeSliceRunning(TIM0_Tick);
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void TimeSliceRunning(uint32_t Tick)
{
TimeSlice_NodeTypeDef *Node = Head;
while (NULL != Node)
{
if (0 == (Tick % Node->Period))
{
Node->RunFlag = 1;
}
Node = Node->Next;
}
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void TimeSlicePolling(void)
{
TimeSlice_NodeTypeDef *Node = Head;
while (NULL != Node)
{
if (1 == Node->RunFlag)
{
Node->RunFlag = 0;
Node->Handler();
}
Node = Node->Next;
}
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void main(void)
{
BSP_Init();
TimeSliceInitTIM();
enableInterrupts();
while (1)
{
TimeSlicePolling();
}
}
任务的管理主要是创建,首先是定义一个任务,它有运行的间隔时间、可运行标志位、任务具体调用的功能函数、以及下一任务节点指针;通过链表的形式将各个节点的任务串连起来管理;其中使用到了malloc和free这两个动态内存分配和释放的函数,这个跟我们在32位MCU使用上还是有些区别的,主是需要定义一个内存池,对内存池进行初始化后才可以正常的运行malloc这些函数……具体的实现代码如下所示:
/* Exported types *****************************************************************************************************/
typedef void (* Function)(void);
/* Exported types *****************************************************************************************************/
typedef struct _Node_Struct
{
uint32_t Period;
uint8_t RunFlag;
Function Handler;
struct _Node_Struct *Next;
} TimeSlice_NodeTypeDef;
/* Private variables **************************************************************************************************/
static uint8_t xdata mempool[1024];
TimeSlice_NodeTypeDef *Head = NULL;
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void TimeSliceStartup(Function Handler, uint32_t Period)
{
TimeSlice_NodeTypeDef *Node = Head;
if (NULL == Head)
{
memset(mempool, 0x00, sizeof(mempool));
init_mempool(mempool, sizeof(mempool));
Head = (TimeSlice_NodeTypeDef *)malloc(sizeof(TimeSlice_NodeTypeDef));
if (NULL == Head)
{
free(Head);
}
else
{
Head->Period = Period;
Head->RunFlag = 0;
Head->Handler = Handler;
Head->Next = NULL;
}
}
else
{
while (NULL != Node->Next)
{
if (Node->Handler == Handler)
{
Node->Period = Period;
return;
}
else
{
Node = Node->Next;
}
}
Node->Next = (TimeSlice_NodeTypeDef *)malloc(sizeof(TimeSlice_NodeTypeDef));
if (NULL != Node->Next)
{
Node = Node->Next;
Node->Period = Period;
Node->RunFlag = 0;
Node->Handler = Handler;
Node->Next = NULL;
}
else
{
free(Node->Next);
}
}
}
2、GPIO输出控制LED、GPIO输入检测KEY输入状态
GPIO是作为MCU的一个最基础的功能,通过新定义提供的低层库函数实现了LED亮灭的控制、通过状态机的方式实现了按键的检测和功能处理,具体代码如下所示:
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void LED_Init(void)
{
GPIO_Init(GPIO4, GPIO_PIN_6, GPIO_MODE_OUT_PP); /* L1->P46 */
GPIO_Init(GPIO4, GPIO_PIN_7, GPIO_MODE_OUT_PP); /* L2->P47 */
GPIO_WriteLow(GPIO4, GPIO_PIN_6);
GPIO_WriteLow(GPIO4, GPIO_PIN_7);
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void KEY_StateHandler(uint8_t Index, uint8_t *State, uint8_t *Count, uint8_t InputLevel, uint8_t ActiveLevel)
{
if (0 == *State)
{
if (InputLevel == ActiveLevel)
{
*Count += 1;
if (*Count >= 5)
{
*Count = 0;
*State = 1;
KEY_EventHandler(Index, 1);
}
}
else
{
*Count = 0;
}
}
else
{
if (InputLevel != ActiveLevel)
{
*Count += 1;
if (*Count >= 5)
{
*Count = 0;
*State = 0;
KEY_EventHandler(Index, 0);
}
}
else
{
*Count = 0;
}
}
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void KEY_Scan(void)
{
static uint8_t State[2] =
{
0, 0
};
static uint8_t Count[2] =
{
0, 0
};
KEY_StateHandler(0, &State[0], &Count[0], GPIO_ReadPin(GPIO3, GPIO_PIN_6), RESET);
KEY_StateHandler(1, &State[1], &Count[1], GPIO_ReadPin(GPIO5, GPIO_PIN_4), RESET);
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void KEY_Init(void)
{
GPIO_Init(GPIO3, GPIO_PIN_6, GPIO_MODE_IN_PU); /* K1->P36 */
GPIO_Init(GPIO5, GPIO_PIN_4, GPIO_MODE_IN_PU); /* K2->P54 */
TimeSliceStartup(KEY_Scan, 10);
}
3、3路PWM输出控制RGB灯,根据人体视觉感观,控制RGB亮度调节、颜色切换
RGB的亮度调节是通过修改PWM的占空比实现的,颜色的切换是通过开关不同的PWM通道实现的,在亮度调节上我们使用了LOG参数的形式进行计算后调节,使人体视觉感观更自然,调节更舒适,具体代码如下所示:
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
double RGB_GetLOG(double Level, double MAX)
{
return pow(10, Level * log10(999) / MAX);
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void RGB_Scan(void)
{
static uint8_t Index = 0;
static uint8_t State = 0, Level = 0, MAX = 100;
switch (Index)
{
case 0:
PWM_IndependentModeConfig(PWM01, RGB_GetLOG(Level, MAX));
PWM_IndependentModeConfig(PWM00, 0);
PWM_IndependentModeConfig(PWM03, 0);
break;
case 1:
PWM_IndependentModeConfig(PWM01, 0);
PWM_IndependentModeConfig(PWM00, RGB_GetLOG(Level, MAX));
PWM_IndependentModeConfig(PWM03, 0);
break;
case 2:
PWM_IndependentModeConfig(PWM01, 0);
PWM_IndependentModeConfig(PWM00, 0);
PWM_IndependentModeConfig(PWM03, RGB_GetLOG(Level, MAX));
break;
default:
break;
}
if (State == 0)
{
if (Level >= MAX)
{
Level = MAX;
State = 1;
}
else
{
Level++;
}
}
else
{
if (Level <= 1)
{
Level = 1;
State = 0;
Index = (Index + 1) % 3;
}
else
{
Level--;
}
}
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void RGB_Init(void)
{
PWM_Init(PWM0_PRESSEL_FHRC_D1, 255);
PWM_IndependentModeConfigEX(PWM00, 0, PWM_OUTPUTSTATE_ENABLE);
PWM_IndependentModeConfigEX(PWM01, 0, PWM_OUTPUTSTATE_ENABLE);
PWM_IndependentModeConfigEX(PWM03, 0, PWM_OUTPUTSTATE_ENABLE);
// PWM_Aligned_Mode_Select(PWM0_Edge_Aligned_Mode);
// PWM_FaultDetectionConfigEX(PWM0_Type, DISABLE);
// PWM_FaultDetectionModeConfigEX(PWM0_Type, PWM0_Immediate_Mode, PWM0_FaultDetectionVoltage_Low, PWM0_WaveFilteringTime_0us);
PWM_CmdEX(PWM0_Type, ENABLE);
TimeSliceStartup(RGB_Scan, 20);
}
这边就是对PWM的PWM_FaultDetectionConfigEX、PWM_FaultDetectionModeConfigEX这两个函数的应用功能不是太了解……
4、1路PWM控制蜂鸣器
对于蜂鸣器的控制我们可以使用将PWM使能或禁止的方式来控制,也可以通过修改PWM占空比的方式来控制;对于这两种方式,都做过尝试:使用将PWM使能或禁止的方式控制便捷,语句调度简单,但在下载MCU程序时,PWM存在触发蜂鸣器的嗒嗒声;而通过修改PWM占空比的方式,在下载程序时蜂鸣器不会误响,但在控制上需要注意,不能以极快的速度去切换PWM的占空比,这样有可能会导致程序卡死或者是MCU卡死(具体哪个卡了,还没分析),参考程序如下:
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void BUZZER_Init(void)
{
#if 0
uint16_t Frequency = 32000000 / BUZZER_PWM_FREQ;
uint16_t Duty = 32000000 / BUZZER_PWM_FREQ * BUZZER_PWM_DUTY / 100;
PWM_DeInit();
PWM_Init(PWM4_PRESSEL_FHRC_D1, Frequency);
PWM_IndependentModeConfigEX(PWM40, Duty, PWM_OUTPUTSTATE_ENABLE);
PWM_CmdEX(PWM4_Type, DISABLE);
#else
PWM_DeInit();
PWM_Init(PWM4_PRESSEL_FHRC_D1, 32000000 / BUZZER_PWM_FREQ);
PWM_IndependentModeConfigEX(PWM40, 0, PWM_OUTPUTSTATE_ENABLE);
PWM_CmdEX(PWM4_Type, ENABLE);
#endif
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void BUZZER_Enable(uint8_t State)
{
#if 0
if (ENABLE == State)
{
PWM_CmdEX(PWM4_Type, ENABLE);
}
else
{
PWM_CmdEX(PWM4_Type, DISABLE);
}
#else
if (ENABLE == State)
{
PWM_IndependentModeConfig(PWM40, 32000000 / BUZZER_PWM_FREQ * BUZZER_PWM_DUTY / 100);
}
else
{
PWM_IndependentModeConfig(PWM40, 0);
}
#endif
}
5、通过芯片的LCD/LED外设功能驱动显示4位8段数码管
新定义的这款MCU不仅支持触摸功能,还带有LCD/LED段码显示功能,每一个段和位在MCU都对应一个显示内存,根据硬件设计在配置好相应的显示参数后,可以直接操作内存显示我们想要的内容,参考代码如下:
/* Private typedef ****************************************************************************************************/
typedef struct
{
char ch;
uint8_t Data;
} LED_CodeTypeDef;
/* Private define *****************************************************************************************************/
/* Private macro ******************************************************************************************************/
/* Private variables **************************************************************************************************/
code LED_CodeTypeDef LED_CODE_TAB[38] =
{
{ ' ', 0x00 },
{ '0', 0x3F },
{ '1', 0x06 },
{ '2', 0x5B },
{ '3', 0x4F },
{ '4', 0x66 },
{ '5', 0x6D },
{ '6', 0x7D },
{ '7', 0x07 },
{ '8', 0x7F },
{ '9', 0x6F },
{ 'A', 0x77 },
{ 'b', 0x7C },
{ 'c', 0x58 },
{ 'C', 0x39 },
{ 'd', 0x5E },
{ 'E', 0x79 },
{ 'F', 0x71 },
{ 'g', 0x6F },
{ 'H', 0x76 },
{ 'h', 0x74 },
{ 'i', 0x04 },
{ 'I', 0x30 },
{ 'J', 0x1E },
{ 'l', 0x30 },
{ 'L', 0x38 },
{ 'n', 0x54 },
{ 'o', 0x5C },
{ 'O', 0x3F },
{ 'P', 0x73 },
{ 'q', 0x67 },
{ 'r', 0x50 },
{ 'S', 0x6D },
{ 't', 0x78 },
{ 'u', 0x1C },
{ 'U', 0x3E },
{ 'y', 0x6E },
{ '-', 0x40 },
};
uint8_t LED_DisplayMode = 0;
/* Private functions **************************************************************************************************/
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void LED_DisplayNumber(uint8_t Index, uint8_t Data)
{
DDIC_Control_COM_TypeDef DDIC_COMn[4] =
{
DDIC_COM3, DDIC_COM2, DDIC_COM1, DDIC_COM0
};
DDIC_Control(DDIC_SEG4, DDIC_COMn[Index], (Data >> 0x00) & 0x01);
DDIC_Control(DDIC_SEG16, DDIC_COMn[Index], (Data >> 0x01) & 0x01);
DDIC_Control(DDIC_SEG18, DDIC_COMn[Index], (Data >> 0x02) & 0x01);
DDIC_Control(DDIC_SEG20, DDIC_COMn[Index], (Data >> 0x03) & 0x01);
DDIC_Control(DDIC_SEG23, DDIC_COMn[Index], (Data >> 0x04) & 0x01);
DDIC_Control(DDIC_SEG6, DDIC_COMn[Index], (Data >> 0x05) & 0x01);
DDIC_Control(DDIC_SEG17, DDIC_COMn[Index], (Data >> 0x06) & 0x01);
DDIC_Control(DDIC_SEG19, DDIC_COMn[Index], (Data >> 0x07) & 0x01);
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void LED_DisplayString(char *str)
{
uint8_t i = 0, Index = 0;
while ((*str != '\0') && (Index < 4))
{
for (i = 0; i < 38; i++)
{
if (*str == LED_CODE_TAB[i].ch)
{
LED_DisplayNumber(Index, LED_CODE_TAB[i].Data);
}
}
str++;
Index++;
}
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void LED_Scan(void)
{
static uint16_t Count = 0;
char str[10];
if (0 == LED_DisplayMode)
{
memset(str, 0, sizeof(str));
sprintf(str, "%04d", Count);
LED_DisplayString(str);
Count = (Count + 1) % 10000;
}
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void LED_Init(void)
{
DDIC_DMOD_Selcet(DMOD_LED);
DDIC_Init(DDIC_DUTYCYCLE_D4,
DDIC_PIN_X0 | DDIC_PIN_X3,
DDIC_PIN_X0 | DDIC_PIN_X2,
DDIC_PIN_X4 | DDIC_PIN_X5 | DDIC_PIN_X6 | DDIC_PIN_X7,
DDIC_PIN_X0 | DDIC_PIN_X1 | DDIC_PIN_X2 | DDIC_PIN_X3);
DDIC_OutputPinOfDutycycleD4(SEG4_27COM0_3);
DDIC_Cmd(ENABLE);
TimeSliceStartup(LED_Scan, 100);
}
6、通过板载的可调节电阻实现ADC检测与显示、通过2个可调节电阻实现比较器的功能
板载两个可调电阻,一个可调电阻是用于ADC采样调节的,另外一个电阻是用来调节比较器的外部比较电压的;通过这两个可调电阻,我们既可以实现ADC的功能,也可以实现比较器的功能,参考代码如下:
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void ADC_Configure(void)
{
ADC_Init(ADC_PRESSEL_3CLOCK, ADC_Cycle_Null);
ADC_EAINConfig(ADC_EAIN_7, ENABLE);
ADC_EAINConfig(ADC_EAIN_15, ENABLE);
ADC_Cmd(ENABLE);
TimeSliceStartup(ADC_Scan, 200);
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
uint16_t ADC_GetADCValue(ADC_Channel_TypeDef Channel)
{
uint16_t Value = 0;
ADC_ChannelConfig(Channel, ENABLE);
ADC_StartConversion();
while (RESET == ADC_GetFlagStatus())
{
_nop_();
}
return (ADC_GetConversionValue());
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void CMP_Scan(void)
{
static uint8_t State = 0;
if (3 == LED_DisplayMode)
{
if (CMPCON & (ACMP_FLAG_CMPSTA)) /* CMP3 > CMPR */
{
if (1 != State)
{
State = 1;
BUZZER_Enable(ENABLE);
}
}
else /* CMP3 < CMPR */
{
if (0 != State)
{
State = 0;
BUZZER_Enable(DISABLE);
}
}
LED_DisplayString("----");
}
}
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void CMP_Init(void)
{
ACMP_Init(ACMP_VREF_8D16VDD, ACMP_VREF_EXTERNAL);
ACMP_Cmd(ENABLE);
TimeSliceStartup(CMP_Scan, 20);
}
7、NTC实时温度检测与显示
NTC也是通过MCU的ADC功能来实现的,首先采样NTC的ADC数据,然后根据NTC的特性表对应的温度进行查表换算,最后通过LED数码管显示出来,参考代码如下:
/* Private variables **************************************************************************************************/
code uint16_t NTC_ADC_MapTable[100] =
{
248 , 262 , 277 , 293 , 310 , 327 , 345 , 364 , 384 , 404 ,
425 , 447 , 470 , 494 , 518 , 543 , 570 , 597 , 624 , 653 ,
683 , 713 , 744 , 776 , 809 , 842 , 877 , 912 , 948 , 984 ,
1022, 1060, 1098, 1137, 1177, 1217, 1258, 1299, 1341, 1383,
1425, 1468, 1511, 1554, 1598, 1641, 1685, 1729, 1772, 1816,
1860, 1903, 1946, 1990, 2033, 2075, 2117, 2159, 2201, 2243,
2283, 2324, 2364, 2403, 2442, 2481, 2519, 2556, 2593, 2629,
2664, 2699, 2734, 2767, 2800, 2833, 2864, 2895, 2926, 2956,
2985, 3013, 3041, 3069, 3095, 3121, 3147, 3172, 3195, 3219,
3242, 3265, 3286, 3308, 3328, 3348, 3368, 3388, 3406, 3424,
};
/***********************************************************************************************************************
* @brief
* @param
* @retval
* @attention
*********************************************************************************************************************/
void ADC_Scan(void)
{
char str[10];
uint16_t i = 0;
uint16_t Value;
if (1 == LED_DisplayMode) /* CMP3 */
{
Value = ADC_GetADCValue(ADC_CHANNEL_15);
memset(str, 0, sizeof(str));
sprintf(str, "%04d", Value);
LED_DisplayString(str);
}
if (2 == LED_DisplayMode) /* NTC */
{
Value = ADC_GetADCValue(ADC_CHANNEL_7);
for(i = 0; i < 99; i++)
{
if((Value >= NTC_ADC_MapTable[i]) && (Value < NTC_ADC_MapTable[i + 1]))
{
break;
}
}
memset(str, 0, sizeof(str));
if(i < 15)
{
sprintf(str, "-%02dC", 15 - i);
}
else
{
sprintf(str, "%03dCC", i - 15);
}
LED_DisplayString(str);
}
}
最后直接贴上完整的工程源代码:
Project_NBK-RD8x3x_NBK-EBS002.zip
(203.31 KB)
最终效果演示视频:
|
此文章已获得独家原创/原创奖标签,著作权归21ic所有,未经允许禁止转载。
打赏榜单
21小跑堂 打赏了 80.00 元 2023-02-15 理由:恭喜通过原创审核!期待您更多的原创作品~
共2人点赞
|
一次玩遍扩展板的所有功能,一文道扩展板全部能力。通过作者扎实的自我能力和新定义强大的开发板结合,将一个51内核的芯片发光发热。