本人刚刚入职,最近使用了华大家的芯片,国产芯片的一些初始化对于一些单片机的新玩家真的算是比较繁琐,有些注释写的也不太容易让人理解
所以我整理了一下官方的资料并加上自己写的一些功能以及额外的注释,如果有使用这款低功耗芯片的可以参考
首先是串口的初始化和使用
void Uart0_Init(void)
{
uint16_t timer=0;
uint32_t pclk=0;
stc_uart_config_t stcConfig;//定义串口结构体
stc_uart_irq_cb_t stcUartIrqCb;//串口中断回调函数结构体
stc_uart_multimode_t stcMulti;//串口多主机模式结构体
stc_uart_baud_config_t stcBaud;//波特率配置结构体
stc_bt_config_t stcBtConfig;//基础定时器配置结构体
DDL_ZERO_STRUCT(stcUartIrqCb);//清空数据函数
DDL_ZERO_STRUCT(stcMulti);
DDL_ZERO_STRUCT(stcBaud);
DDL_ZERO_STRUCT(stcBtConfig);
Gpio_InitIOExt(0,1,GpioDirOut,FALSE,FALSE,FALSE,TRUE); //配置01引脚为输入模式RX
Gpio_InitIOExt(0,2,GpioDirOut,FALSE,FALSE,FALSE,TRUE);//配置02引脚为输出模式TX
//通道端口配置
Gpio_SetFunc_UART0_RXD_P01();//RX输入
Gpio_SetFunc_UART0_TXD_P02();//TX输出
//外设时钟使能
Clk_SetPeripheralGate(ClkPeripheralBt,TRUE);//模式0/2可以不使能
Clk_SetPeripheralGate(ClkPeripheralUart0,TRUE);//使能串口时钟
stcUartIrqCb.pfnRxIrqCb = RxIntCallback;//设置接收中断函数
stcUartIrqCb.pfnTxIrqCb = NULL;//设置发送中断为空
stcUartIrqCb.pfnRxErrIrqCb = ErrIntCallback;//设置接收错误中断函数
stcConfig.pstcIrqCb = &stcUartIrqCb;//将中断函数结构体指针赋值给串口配置
stcConfig.bTouchNvic = TRUE;//NVIC中断控制器使能标志
stcConfig.enRunMode = UartMode1;//测试项,更改此处来转换4种模式测试
//stcMulti.enMulti_mode = UartNormal;//测试项,更改此处来转换多主机模式,mode2/3才有多主机模式
stcConfig.pstcMultiMode = &stcMulti;//将中断回调函数结构体指针赋值给串口配置结构体
stcBaud.bDbaud = 0u;//不使能
stcBaud.u32Baud = 9600u;//设置波特率为9600bps
stcBaud.u8Mode = UartMode1; //计算波特率需要模式参数
pclk = Clk_GetPClkFreq();//获取外设始终频率
timer=Uart_SetBaudRate(UARTCH0,pclk,&stcBaud);//计算波特率对应得定时器
stcBtConfig.enMD = BtMode2;//基础定时器模式为Mode2
stcBtConfig.enCT = BtTimer;//基础定时器工作在定时器模式
Bt_Init(TIM0, &stcBtConfig);//调用basetimer0设置函数产生波特率
Bt_ARRSet(TIM0,timer);//设计基础定时器0得自动重载值
Bt_Cnt16Set(TIM0,timer);//设置基础定时器0得计数值
Bt_Run(TIM0);//启动基础定时器0
Uart_Init(UARTCH0, &stcConfig);//初始化串口0
Uart_EnableIrq(UARTCH0,UartRxIrq);//使能串口0中断
Uart_ClrStatus(UARTCH0,UartRxFull);//清除缓冲区满标志
Uart_EnableFunc(UARTCH0,UartRx);//使能串口0接收功能
}
这里配置串口时要注意引脚对应通道问题,如果使用STM32系列的芯片习惯了这里可能会不太适应,引脚对应的通道比较乱,有时候通道对应的引脚只是把接受和发送颠倒了一下
使用非常简单发送出去就可以,但是要注意,你配置的模式需不需要计算数据位,还有这里面的串口发送一次只能发送一个字节,建议使用printf()进行输出
然后是ADC的初始化和使用
int32_t ADC_Init(void)
{
stc_adc_cfg_t stcAdcCfg;
stc_adc_norm_cfg_t stcAdcNormCfg;
DDL_ZERO_STRUCT(stcAdcCfg);
DDL_ZERO_STRUCT(stcAdcNormCfg);
//Clk_SwitchTo(ClkRCL);
//Clk_SetRCHFreq(ClkFreq24Mhz);
//Clk_SwitchTo(ClkRCH);
if (Ok != Clk_SetPeripheralGate(ClkPeripheralGpio, TRUE))
{
return Error;
}
if (Ok != Clk_SetPeripheralGate(ClkPeripheralAdcBgr, TRUE))
{
return Error;
}
Gpio_SetAnalog(2, 4, TRUE);
Adc_Enable();
M0P_BGR->CR_f.BGR_EN = 0x1u;//BGR必须使能
M0P_BGR->CR_f.TS_EN = 0x0u;
delay100us(1);
stcAdcCfg.enAdcOpMode = AdcNormalMode; //单次采样模式
stcAdcCfg.enAdcClkSel = AdcClkSysTDiv1; //PCLK
stcAdcCfg.enAdcSampTimeSel = AdcSampTime4Clk; //4个采样时钟
stcAdcCfg.enAdcRefVolSel = RefVolSelAVDD; //外部电源3.3V 参考电压:内部2.5V(avdd>3V,SPS<=200kHz) SPS速率 = ADC时钟 / (采样时钟 + 16CLK)
stcAdcCfg.bAdcInBufEn = FALSE; //电压跟随器如果使能,SPS采样速率 <=200K
stcAdcCfg.u32AdcRegHighThd = 0u; //比较阈值上门限
stcAdcCfg.u32AdcRegLowThd = 0u; //比较阈值下门限
stcAdcCfg.enAdcTrig0Sel = AdcTrigDisable; //ADC转换自动触发设置
stcAdcCfg.enAdcTrig1Sel = AdcTrigDisable;
Adc_Init(&stcAdcCfg);
stcAdcNormCfg.enAdcNormModeCh = AdcExInputCH0; //通道0 P24
stcAdcNormCfg.bAdcResultAccEn = FALSE;
Adc_ConfigNormMode(&stcAdcCfg, &stcAdcNormCfg);
}
Adc_Start();//ADC开始转换
while(FALSE != Adc_PollBusyState());//查询ADC状态是否转换完成
Adc_GetResult(&u16AdcResult);//获取电压值
AdcResultH=u16AdcResult>>8;//取电压值高八位
AdcResultL=u16AdcResult;//取电压值低八位
这里要注意,如果要使用串口查看获取的电压值,需要把16位ADC的电压值通过计算转换为8位(一字节)
然后是外部中断的使用
// 初始化外部IO P32
// Gpio_InitIOExt(3,2, GpioDirIn, TRUE, FALSE, FALSE, 0);//输入模式 下拉
// Gpio_SetIO(3, 2, TRUE);//输出高电平,P32使能 外部中断
// 开启GPIO外部中断
// Gpio_ClearIrq(3, 2);//清除中断标志位
// Gpio_EnableIrq(3, 2, GpioIrqLow);//中断设置 P32低电平触发
// EnableNvic(PORT3_IRQn, DDL_IRQ_LEVEL_DEFAULT, TRUE);//中断使能 通道3 第二优先级 每十个引脚一个通道
这里需要注意这款芯片的外部中断通道为每十个一组,P01为通道0,P33为通道3
这里是外部中断的服务函数
void Gpio_IRQHandler(uint8_t u8Param)//中断服务函数
{
*((uint32_t *)((uint32_t)&M0P_GPIO->P3ICLR + u8Param * 0x40)) = 0;
Gpio_SetIO(0, 3, TRUE);//点亮D2
delay1ms(2000);
Gpio_ClearIrq(3,2);//清除中断标志位
}
然后是RTC的初始化以及使用
void rtc_Init(void)
{
stc_rtc_config_t stcRtcConfig;//定义RTC结构体
stc_rtc_irq_cb_t stcIrqCb;//定义RTC中断回调函数结构体
stc_rtc_time_t stcTime;//RTC时间结构体
stc_rtc_alarmset_t stcAlarm;//RTC闹钟设置结构体
stc_rtc_cyc_sel_t stcCycSel;//RTC定时周期结构体
DDL_ZERO_STRUCT(stcRtcConfig);//清空数据函数
DDL_ZERO_STRUCT(stcIrqCb);
DDL_ZERO_STRUCT(stcAlarm);
DDL_ZERO_STRUCT(stcTime);
DDL_ZERO_STRUCT(stcCycSel);
DDL_ZERO_STRUCT(stcLpmCfg);
stcLpmCfg.enSLEEPDEEP = SlpDpEnable;//使能深度睡眠
stcLpmCfg.enSLEEPONEXIT = SlpExtEnable;//在退出中断时进入睡眠
// Clk_SetPeripheralGate(ClkPeripheralGpio,TRUE);//使能GPIO时钟
// Gpio_InitIO(T1_PORT,T1_PIN,GpioDirOut);//初始化IO口为输出
// Gpio_SetIO(T1_PORT,T1_PIN,1);
// Gpio_InitIO(3,3,GpioDirIn);
Clk_Enable(ClkRCL, TRUE);//开启内部晶振
Clk_SetPeripheralGate(ClkPeripheralRtc,TRUE);//使能rtc时钟
stcRtcConfig.enClkSel = RtcClk32;//RTC时钟选择为内部RTC
stcRtcConfig.enAmpmSel = Rtc24h;//RTC工作在24小时制
stcCycSel.enCyc_sel = RtcPrads;//RTC定时周期选择为预分频
stcCycSel.enPrds_sel = Rtc_1Min;//RTC预分频选择为1分钟
#if 0
stcCycSel.enCyc_sel = RtcPradx;
stcCycSel.u8Prdx = 1u;
#endif
stcRtcConfig.pstcCycSel = &stcCycSel;
#if 1
Rtc_DisableFunc(RtcCount);//关闭RTC计数功能
stcAlarm.u8Minute = 0x01;
stcAlarm.u8Hour = 0x00;
stcAlarm.u8Week = 0x00;
Rtc_DisableFunc(RtcAlarmEn);//关闭RTC闹钟使能功能
Rtc_EnAlarmIrq(Rtc_AlarmInt_Enable);//使能中断
Rtc_SetAlarmTime(&stcAlarm);//设置时间
Rtc_EnableFunc(RtcAlarmEn);//使能闹钟
#endif
stcTime.u8Year = 0x23;
stcTime.u8Month = 0x08;
stcTime.u8Day = 0x07;
stcTime.u8Hour = 0x09;
stcTime.u8Minute = 0x30;
stcTime.u8Second = 0x00;
stcTime.u8DayOfWeek = Rtc_CalWeek(&stcTime.u8Day);//计算时间对应得星期
stcRtcConfig.pstcTimeDate = &stcTime;
stcIrqCb.pfnAlarmIrqCb = RtcAlarmCb;//使能各种回调函数
stcIrqCb.pfnTimerIrqCb = RtcCycCb;
stcRtcConfig.pstcIrqCb = &stcIrqCb;
stcRtcConfig.bTouchNvic = TRUE;
Rtc_DisableFunc(RtcCount);
Rtc_Init(&stcRtcConfig);
Rtc_EnableFunc(RtcCount);
//#if 1
// while(1 == Gpio_GetIO(3,3));//注意:此处用户随便屏蔽,进入深度休眠模式。
// Lpm_Config(&stcLpmCfg);
// Lpm_GotoLpmMode();
//#endif
}
这里进入低功耗模式应该在主函数中进行,并且在每次开机进入低功耗模式之前给足下载程序的时候,或者设定唤醒MCU的任务
芯片自带的RTC周期以及闹钟的中断回调函数已经在初始化中使能完毕可以直接使用
static void RtcCycCb(void)//RTC周期中断回调函数
{
cyccnt++;
Gpio_SetIO(0, 3, FALSE);//测试周期中断D2
flg = ~flg;
Gpio_SetIO(0,3,flg);
}
static void RtcAlarmCb(void)//RTC闹钟中断回调函数
{
}
作者也是刚刚接触这款芯片,因为觉得定义的比较繁琐,所以把自己寻找的理解的发表,希望有助于初学者学习这款国产芯片