本帖最后由 lyj336 于 2020-6-16 22:55 编辑

之前一直忙于工作冷落了MM32的开发板,这几天闲下来,写了些代码测试板载外设是否能正常工作,也体验了一番MM32库函数。接下来我分享一下这几天我做的东西和我的想法。
一、MM32主控芯片使用感受
这次申请的是MM32W373系列的板子跟STM32很类似,开发方式也一样,如果使用过STM32,MM32系统的芯片就可以简单上手。我从数据手册对比了一下MM32L3系列和STM32F103系列的芯片,发现它们的总线架构很类似,很多外设存储器映射都一样。
MM32存储器映射.png
                (1)MM32L3部分存储器映射
F10x系列存储器映射.png
                (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);
  • 复制代码
    2.按键测试简单说明
    一样的,从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
  • 复制代码
    3.Uart测试简单说明
    开发板上的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;
  • }
  • 复制代码
    串口使用了接收中断,并以接收到换行"\n"字符,为结束符,然后置位接收成功标志位,在主程序中做处理。
    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);
  •                 }
  • }
  • 复制代码
    4.adc测试简单说明
    开发板的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;
  • }
  • 复制代码
    5.蜂鸣器测试简单说明
    蜂鸣器控制引脚接到了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);
  • }
  • 复制代码
    6.主程序简单说明
    主程序里先初始化硬件,然后循环执行按键和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  有兴趣可以下载。
    测试结果
    MM32测试结果.png