之前一直忙于工作冷落了MM32的开发板,这几天闲下来,写了些代码测试板载外设是否能正常工作,也体验了一番MM32库函数。接下来我分享一下这几天我做的东西和我的想法。
一、MM32主控芯片使用感受
这次申请的是MM32W373系列的板子跟STM32很类似,开发方式也一样,如果使用过STM32,MM32系统的芯片就可以简单上手。我从数据手册对比了一下MM32L3系列和STM32F103系列的芯片,发现它们的总线架构很类似,很多外设存储器映射都一样。
(1)MM32L3部分存储器映射
(2)STM32F10x部分存储器映射
这两种芯片还是很有差异的,MM32W373系列芯片内部集成有2.4Ghz的射频芯片。两种芯片有些外设寄存器一样,有些是有差异的。GPIO的外设寄存器是一样的,但是UART外设寄存器就不一样。MM32L3系列的库函数和STMF10x系列库函数能不能共用呢?有些可以,比如GPIO口,有些就不行比如UART。二、测试程序简单说明
官网上没有MM32W3系列芯片的例程,但是听说MM32W3和MM32L3是一样的内核,所以使用了MM32L3的例程来做测试。这是的小测试主要有以下几个功能:
①按下按键,对应的LED灯反转亮灭
②通过串口助手,向开发板发送命令BEEPON、BEEPOFF控制蜂鸣器
③输入命令GETADC,获取ADC检测的值
④输入命令TESTEEP,测试板载的EEPROM。
1.LED测试简单说明
从MM32L3移植过来的例程,需要把LED引脚定义改成MB-021开发板上的引脚。MB-021上LED灯使用的引脚为GPIOA_15、GPIOC_10、GPIOC_11、GPIO12
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(GPIOC, &GPIO_InitStructure);
一样的,从MM32L3移植过来的程序,需要把按键引脚定义改了,需要注意的是K1接到PA0可以做唤醒功能,K1在外部做了上拉,K2、K3、K4做了下拉。
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//PB1,K1(WK_UP)
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置成下拉输入
- GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB1
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_10 | GPIO_Pin_11; //PB2,PB10,PB11,K2,K3,K4
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
- GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB.2,10,11
开发板上的Uart输出口接的是芯片的UART2,所以程序中要使用的是UART。我使用了printf函数直接向串口输出信息,所以重定义fputc函数。
- int fputc(int ch, FILE *f)
- {
- while((UART2->CSR & UART_IT_TXIEN) == 0); //循环发送,直到发送完毕
- UART2->TDR = (ch & (uint16_t)0x00FF);
- return ch;
- }
- void UART2_IRQHandler(void)
- {
- uint8_t i=0;
- if(UART_GetFlagStatus(UART2,UART_IT_RXIEN)==SET)
- {
- if(UART_ReceiveData(UART2)=='\n')
- {
- UART_Finish_FLAG=1;
- RecBuffer[sp]='\0';
- sp=0;
- }
- else
- {
- if(sp==0)
- {
- for(i=0;i<REVBUFFSIZE;i++)
- {
- SendData[i]='\0';
- RecBuffer[i]='\0';
- }
- }
- RecBuffer[sp]=UART_ReceiveData(UART2);
- SendData[sp]=RecBuffer[sp];
- sp++;
- }
- }
- if(UART_GetITStatus(UART2,UART_IT_RXIEN)!=RESET)
- {
- UART_ClearITPendingBit(UART2,UART_IT_RXIEN);
- }
- }
开发板的adc引脚接的是PA5引脚,初始化时使用配置为单次模式。每次需要读取时使用ADC_SoftwareStartConvCmd(ADC1, ENABLE)使能ADC转换,这里测量多次取平均值。
- u16 ADC1_SingleChannel_Get(uint8_t ADC_Channel_x)
- {
- u16 puiADData;
- ADC_SoftwareStartConvCmd(ADC1, ENABLE);
- while(!(ADC1->ADSTA & ADC_FLAG_EOC));
- puiADData = ADC1->ADDATA & 0xfff;
- ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
- /*ADCR寄存器的ADST位失能,软件转换结束*/
- return puiADData;
- }
- u16 Get_Adc_Average(uint8_t ADC_Channel_x, uint8_t times)
- {
- u32 temp_val = 0;
- u8 t;
- u8 delay;
- for(t = 0; t < times; t++)
- {
- temp_val += ADC1_SingleChannel_Get(ADC_Channel_x);
- for(delay = 0; delay < 100; delay++);
- }
- return temp_val / times;
- }
蜂鸣器控制引脚接到了PA8引脚,这里使用的TIM的PWM模式控制蜂鸣器发声。当需要蜂鸣器发声时调用TIM_CtrlPWMOutputs(TIM1, ENABLE);关闭蜂鸣器时关闭TIM_CtrlPWMOutputs(TIM1, DISABLE);
- void TIM1_PWM_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
- RCC_ClocksTypeDef RCC_Clocks;
- RCC_GetClocksFreq(&RCC_Clocks);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1 | RCC_APB2Periph_AFIO, ENABLE);
- //设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM3_CH1
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- TIM_TimeBaseStructure.TIM_Period = (1000 - 1); //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K
- TIM_TimeBaseStructure.TIM_Prescaler = (RCC_Clocks.SYSCLK_Frequency / 1000000 - 1);; //设置用来作为TIMx时钟频率除数的预分频值 不分频
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;; //设置时钟分割:TDTS = Tck_tim
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
- TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
- TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
- TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
- TIM_OC1Init(TIM1, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
- TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //CH1预装载使能
- TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器
- TIM_Cmd(TIM1, ENABLE); //使能TIM1
- TIM_CtrlPWMOutputs(TIM1, DISABLE);
- }
主程序里先初始化硬件,然后循环执行按键和LED测试部分程序、检查是否收到数据,如果收到数据,根据收到的数据执行相应的命令。
- int main(void)
- {
- u8 key_flag=0;
- u8 len;
- delay_init();
- LED_Init();
- KEY_Init();
- uart_initwBaudRate(UART2,115200);
- TIM1_PWM_Init();
- TIM_SetCompare1(TIM1, 200);
- I2C_Initializes();
- ADC1_Init( ADC_Channel_5);
- Beep_init();
- delay_ms(1000);
- printf("\n This is a MM32 Test Demo!!!\n");
- printf("\n You can input the following command:\n");
- printf("\n1.BEEPON\n");
- printf("\n2.BEEPOFF\n");
- printf("\n3.GETADC\n");
- printf("\n4.TESTEEP\n");
- while(1)
- {
- Led_Key_Test();
- if(UART_Finish_FLAG)
- {
- len=strlen(RecBuffer)-1;
- if(!strncmp(RecBuffer,"BEEPON",len))
- {
- Beep_On();
- printf("BEEPON_OK \n");
- }
- else if(!strncmp(RecBuffer,"BEEPOFF",len))
- {
- Beep_Off();
- printf("BEEPOFF_OK \n");
- }
- else if(!strncmp(RecBuffer,"GETADC",len))
- {
- Get_AdcValue();
- printf("GETADC_OK \n");
- }
- else if(!strncmp(RecBuffer,"TESTEEP",len))
- {
- printf("TESTEEP_OK \n");
- ee_Test();
- }
- else
- {
- printf("Input error!!!\n");
- printf("Please Input again!!!\n");
- }
- UART_Finish_FLAG=0;
- }
- }
- }
这次因为时间有限,所以只是对板载硬件做了一个简单的测试。开发板上的FLASH一直没成功,不知道是什么原因,拨码开关也拨了还是不行,有时间检查Flash部分电路是不是坏了。代码源码放于https://gitee.com/Liyj_336/MM32_Test.git 有兴趣可以下载。
测试结果