打印
[牛人杂谈]

新唐M051学习

[复制链接]
3538|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 zhuomuniao110 于 2016-7-26 23:57 编辑

从杂志上看到介绍新唐M051单片机的一篇**,说M051是8位机的价格32位机的性能。从网上一查,一片M0516LBN仅售7元左右跟一片8位单片机价格差不多的。而且功能比单片机还多速度还快。于是从网上买了个Nu-Link 仿真器(用于往M051里烧写程序)和M0516LBN转51的开发板,就是把贴片的转换成直插模式并且引脚的排列顺序跟51单片机一样,据说如果你会51单片机,用这个开发板学习M051是很容易入门的。过了几天设备到手,迫不及待先试试。
        首先安装编程环境,我用的是MDK5.0。MDK可以跟C51装到同一个目录,这样既可以写C51的程序也可以写M051程序了。
         第二步去新唐的官网下载 Nu-Link Driver for Keil RVMDK V1.24.6211.zip 仿真器的驱动,并安装好。
         第三部下载M051 SeriesBSP_CMSIS_V2.01.002.zip  和 M051 SeriesBSP_DirectRegisterAccess_EN_V1.01.003.zip,这两个是M051的库文件。据说用CMSIS库就像ARM M3的编程方式差不多(我没用过M3),DirectRegisterAccess库是直接操作寄存器跟51单片机的编程方式差不多。问了问高手,他们建议用CMSIS,因为更简单方便。我两个都装上了。这两个文件直接解压C盘即可,路径要记住,要在mdk里面填写。
        打开MDK,新建一个项目,取名TEST,然后出现下图,点OK。

出现选择CPU对话框,找到M0516LBN,点OK.

然后下面对话框点yes。

然后就进入MDK的主界面了。再新建一个空文档,并保存,取名为main.c
在Source Group 1上点右键选择Add Existing Files to Group ,把main.c加进来。
   


点击工具栏上的   这个图标。做如下设置。


沙发
zhuomuniao110|  楼主 | 2016-7-26 23:51 | 只看该作者

新唐M051学习

本帖最后由 zhuomuniao110 于 2016-7-26 23:57 编辑

下图的include paths里面写上刚才解压的 M051 SeriesBSP_CMSIS_V2.01.002.zip的路径。我写的是:
C:KeilM051SeriesBSP_CMSIS_v2.01.002M051SeriesBSP_CMSIS_v2.01.002LibM051SeriesCMSISCM0DeviceSupportNuvotonM051Series;C:KeilM051SeriesBSP_CMSIS_v2.01.002M051SeriesBSP_CMSIS_v2.01.002LibM051SeriesStdDriverinc

下图在scatter file里写:--map --first='startup_M051Series.o(RESET)' --datacompressor=off --info=inline --entry Reset_Handler

选择Nuvoton Nu-Link Debugger,然后点Settings按钮。


然后在main.c里输入以下代码
#include
void SystemInit(void)
{}
int main(void)
{
        //设置P2.0为强推挽输出
_GPIO_SET_PIN_MODE(P2, 0, GPIO_PMD_OUTPUT);
    while(1)
    {
        //让P2.0交替输出高低电平。把LED灯的正极接到P2.0负极接地,LED就会一闪一闪的。
P20 = 1;
SYS_SysTickDelay(500000);
P20 = 0;
SYS_SysTickDelay(500000);      
    }   
}

然后按Ctrl+F5就可以单步调试程序了。如果你没有设置断点的话,这时候LED就会一闪一闪的。

如果不想调试,想直接把程序烧入芯片做如下设置。


然后再点工具栏上的 按钮。

使用特权

评论回复
板凳
zhuomuniao110|  楼主 | 2016-7-26 23:53 | 只看该作者
今天学习PWM,把M051的手册中关于PWM的那一章反反复复看了好几遍,还是看的云里雾里,最后竟然看的打起盹来。后来觉的差不多了,打算动手写个呼吸灯程序,巩固一下学习成果。
      顾名思义,灯光在微电脑控制之下完成由亮到暗又由暗变亮的逐渐变化,感觉像是在呼吸。
      LED等插在P2.0口上(PWM0) 。如下图。



/*********************************************************************************************
程序名:  PWM实验   用PWM制作呼吸灯
编写人:  闪闪发光的金子
编写时间:2014年2月21日
硬件支持:M0516LNB 12MHz晶体
接口说明:    P2.0接LED正极
---------------------------------------------------

#include
#include
#define PLLCON_SETTING      SYSCLK_PLLCON_50MHz_XTAL
#define PLL_CLOCK           50000000

    uint16_t g_u16PWMValue;
   
void SYS_Init(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init System Clock                                                                                       */
/*---------------------------------------------------------------------------------------------------------*/
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Enable External XTAL (4~24 MHz) */
    SYSCLK->PWRCON |= SYSCLK_PWRCON_XTL12M_EN_Msk;

    /* Waiting for 12MHz clock ready */
    SYS_WaitingForClockReady( SYSCLK_CLKSTATUS_XTL12M_STB_Msk);

    /* Switch HCLK clock source to XTAL */
    SYSCLK->CLKSEL0 = SYSCLK_CLKSEL0_HCLK_XTAL;

    /* Set PLL to power down mode and PLL_STB bit in CLKSTATUS register will be cleared by hardware.*/
    SYSCLK->PLLCON|= SYSCLK_PLLCON_PD_Msk;

    /* Set PLL frequency */        
    SYSCLK->PLLCON = PLLCON_SETTING;

    /* Waiting for clock ready */
    SYS_WaitingForClockReady(SYSCLK_CLKSTATUS_PLL_STB_Msk);

    /* Switch HCLK clock source to PLL */
    SYSCLK->CLKSEL0 = SYSCLK_CLKSEL0_HCLK_PLL;

    /* Enable IP clock */
    //设置PWM0、PWM1的时钟源      
    SYSCLK->APBCLK = SYSCLK_APBCLK_PWM01_EN_Msk;

    /* Select IP clock source */
    SYSCLK->CLKSEL1 = SYSCLK_CLKSEL1_PWM01_XTAL;

    /* Reset PWMB channel0~channel3 */                    
    SYS->IPRSTC2 = SYS_IPRSTC2_PWM47_RST_Msk;                    
    SYS->IPRSTC2 = 0;      


    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */
    //SystemCoreClockUpdate();
    PllClock        = PLL_CLOCK;            // PLL
    SystemCoreClock = PLL_CLOCK / 1;        // HCLK
    CyclesPerUs     = PLL_CLOCK / 1000000;  // For SYS_SysTickDelay()

/*---------------------------------------------------------------------------------------------------------*/
/* Init I/O Multi-function                                                                                 */
/*---------------------------------------------------------------------------------------------------------*/
    /* P2.0 for PWM0 */
    SYS->P2_MFP = SYS_MFP_P20_PWM0 ;



    /* Lock protected registers */
    SYS_LockReg();
}
void PWMA_Init(void)
{
    //配置预分频器 (PPR)
    PWMA->PPR = PWM_PPR_CP01(30) ;
    //配置时钟选择器(CSR)
    PWMA->CSR = PWM_CSR_CSR0(PWM_CSR_DIV16);

    /* Enable PWM0  counter. We must set PWM mode before setting CNR, CMR. */
    //如果设置PWM_PCR_CH0MOD_AUTO_RELOAD ,当PWM计数器达到0,自动重载CNR0的值到PWM计数器
    PWMA->PCR = PWM_PCR_CH0EN_Msk | PWM_PCR_CH0MOD_AUTO_RELOAD;

    //频率计算公式
    /* PWM0 = 12000000 / 30 / 16 / 200 =    125Hz */
        PWMA->CNR0= 200;   //配置PWM计数器寄存器 (CNR) 设定PWM周期
    PWMA->CMR0= 100;   //配置比较器寄存器(CMR) 设定PWM占空比

    /* Enable PWM channle 0  Output */
    //配置相应的GPIO管脚为PWM功能(使能 POE 和禁用CAPENR).
    PWMA->POE = PWM_POE_PWM0_Msk;
}


int main(void)
{
    uint16_t i,j;
    SYS_Init();
    PWMA_Init();
    while(1)
    {
      //下面有小到大 然后由大到小 循环改变占空比大小,LED灯就会慢慢变亮,然后又慢慢变暗。
      //注意CMR的值不能大于CNR
        for (g_u16PWMValue = 1;g_u16PWMValue<200;g_u16PWMValue++)   
        {      
            PWMA->CMR0 = g_u16PWMValue;
            for(i=0;i<500;i++)  //延时
                for(j=0;j<100;j++);
        }
        for (g_u16PWMValue = 199;g_u16PWMValue>0;g_u16PWMValue--)   
        {      
            PWMA->CMR0 = g_u16PWMValue;
            for(i=0;i<500;i++)  //延时
                for(j=0;j<100;j++);
        }
    }
}

使用特权

评论回复
地板
zhuomuniao110|  楼主 | 2016-7-26 23:58 | 只看该作者
根据原来用51单片机写LCD160的经验今天用M051的程序重新整理了一遍,并把8位总线和4位总线的的程序整合到一起。从吃完晚饭就坐这,现在都11点多了,整整搞了一个晚上,废话不多说了,抓紧写完睡觉。
1602采用标准的16脚接口,其中:第1脚:VSS为电源地
第2脚:VCC接5V电源正极
第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,使用时可以通过一个10K的电位器调整对比度。我用的这款LCD直接接地,对比度是最佳的,省了不少事。
第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。
第6脚:E(或EN)端为使能端。
第7~14脚:D0~D7为8位双向数据端。
第15脚:背光正极。
第16脚:背光负极。

使用特权

评论回复
5
zhuomuniao110|  楼主 | 2016-7-27 00:00 | 只看该作者
下图是LCD1602跟M0516的连接图。4总线的D0-D3悬空,D4-D7分别接一个IO的高4位也就是第4-第7位。M0516的这个IO的低4位还可以正常作为其他用途,这样就省了4个IO口。



下面是接8位总线的实物图及显示效果图。



下面是接4位总线的实物图及显示效果图。


使用特权

评论回复
6
zhuomuniao110|  楼主 | 2016-7-27 00:01 | 只看该作者
#include <M051Series.h>
#define PLLCON_SETTING      SYSCLK_PLLCON_50MHz_XTAL
#define PLL_CLOCK           50000000

//#define LCD1602_BUS_NUM 8   //8位数据总线,DB0-DB7 按顺序接到一个IO口的 0-7位
//4位总线,DB4 - DB7 按顺序接到一个IO口的 4-7位,液晶上的DB0-DB3空着,IO口上的0-3位可以正常作为其他用途
#define LCD1602_BUS_NUM 4
#define    LCD1602_DATA_PORT        P1->DOUT            // LCD1602的数据总线
#define LCD1602_RS    P30               // LCD1602的RS
#define LCD1602_RW    P31               // LCD1602的RW
#define LCD1602_E     P32               // LCD1602的E控制线
#define LCD1602_Busy  P17                   // 定义LCD1602的测忙线,应该是LCD1602_DB0_DB7的第8位IO口

void SYS_Init(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init System Clock                                                                                       */
/*---------------------------------------------------------------------------------------------------------*/
    /* Unlock protected registers */
    SYS_UnlockReg();
    /* Enable External XTAL (4~24 MHz) */
    SYSCLK->PWRCON |= SYSCLK_PWRCON_XTL12M_EN_Msk;
    /* Waiting for 12MHz clock ready */
    SYS_WaitingForClockReady( SYSCLK_CLKSTATUS_XTL12M_STB_Msk);
    /* Switch HCLK clock source to XTAL */
    SYSCLK->CLKSEL0 = SYSCLK_CLKSEL0_HCLK_XTAL;

    /* Set PLL to power down mode and PLL_STB bit in CLKSTATUS register will be cleared by hardware.*/
    SYSCLK->PLLCON|= SYSCLK_PLLCON_PD_Msk;
    /* Set PLL frequency */        
    SYSCLK->PLLCON = PLLCON_SETTING;

    /* Waiting for clock ready */
    SYS_WaitingForClockReady(SYSCLK_CLKSTATUS_PLL_STB_Msk);

    /* Switch HCLK clock source to PLL */
    SYSCLK->CLKSEL0 = SYSCLK_CLKSEL0_HCLK_PLL;

    /* Enable IP clock */        
    SYSCLK->APBCLK = SYSCLK_APBCLK_PWM01_EN_Msk;
    /* IP clock source */
    SYSCLK->CLKSEL1 = SYSCLK_CLKSEL1_PWM01_XTAL;


    /* Reset PWMB channel0~channel3 */                    
    SYS->IPRSTC2 = SYS_IPRSTC2_PWM47_RST_Msk;                    
    SYS->IPRSTC2 = 0;      




    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */
    //SystemCoreClockUpdate();
    PllClock        = PLL_CLOCK;            // PLL
    SystemCoreClock = PLL_CLOCK / 1;        // HCLK
    CyclesPerUs     = PLL_CLOCK / 1000000;  // For SYS_SysTickDelay()

/*---------------------------------------------------------------------------------------------------------*/
/* Init I/O Multi-function                                                                                 */
/*---------------------------------------------------------------------------------------------------------*/
    /* P2.0 for PWM0 */
    //P2.0接LCD1602的背光
    SYS->P2_MFP = SYS_MFP_P20_PWM0 ;
    /* Lock protected registers */
    SYS_LockReg();

}

void PWMA_Init(void)

{
    PWMA->PPR = PWM_PPR_CP01(30) ;
    PWMA->CSR = PWM_CSR_CSR0(PWM_CSR_DIV16);
    //P2.0接LCD1602的背光,可以用PWM进行调光。
    /* Enable PWM0 counter. We must set PWM mode before setting CNR, CMR. */
    PWMA->PCR = PWM_PCR_CH0EN_Msk | PWM_PCR_CH0MOD_AUTO_RELOAD;
    /* PWM0 = 12000000 / 30 / 16 / 200 =    125Hz */
        PWMA->CNR0= 200;
    PWMA->CMR0= 180;

    /* Enable PWM channle 0 Output */
    PWMA->POE = PWM_POE_PWM0_Msk;
}

//********************************************************************************************
// 读LCD忙程序 [底层协议] // (所有底层协议都无需关注)
// LCD1602测忙,若LCD1602处于忙状态,本函数将等待至非忙状态
//********************************************************************************************/
void LCD1602_TestBusy(void){
    LCD1602_DATA_PORT = 0xff;       //设备读状态
    SYS_SysTickDelay(5);
    LCD1602_RS = 0;
    SYS_SysTickDelay(5);
    LCD1602_RW = 1;
    SYS_SysTickDelay(5);
    LCD1602_E = 1;
    while(LCD1602_Busy);        //等待LCD不忙
    LCD1602_E = 0;              //
}
//向LCD1602写入一个指令或者数据
//R_S 1是数据  0是命令
void LCD1602_WriteByte(uint8_t R_S, uint8_t byte)
{
      LCD1602_TestBusy();
        LCD1602_RS = R_S;
        LCD1602_RW = 0;
        #if (LCD1602_BUS_NUM == 8)  //8位总线
            LCD1602_DATA_PORT = byte;
            SYS_SysTickDelay(10);
            LCD1602_E = 1;
            SYS_SysTickDelay(10);
            LCD1602_E = 0;
        #elif (LCD1602_BUS_NUM == 4) //4位总线
            LCD1602_DATA_PORT &= 0x0f; //高四位清0
            LCD1602_DATA_PORT |= (byte&0xf0);//送入高四位数据
            SYS_SysTickDelay(5);
            LCD1602_E = 1;
            SYS_SysTickDelay(5);
            LCD1602_E = 0;      

            LCD1602_DATA_PORT &= 0x0f; //高四位清0
            LCD1602_DATA_PORT|=(byte<<4&0xf0);//送入低四位数据
            SYS_SysTickDelay(5);
            LCD1602_E = 1;
            SYS_SysTickDelay(5);
            LCD1602_E = 0;      
        #endif
}
//********************************************************************************************
// 写指令程序 //
// 向LCD1602写命令 本函数需要1个指令集的入口参数 //
//********************************************************************************************/
void LCD1602_WriteCMD(uint8_t LCD1602_command) {
    LCD1602_WriteByte(0x00,LCD1602_command);
}
//********************************************************************************************
// 写数据程序 //
// 向LCD写数据 //
//********************************************************************************************/
void LCD1602_WriteData(uint8_t LCD1602_data){
    LCD1602_WriteByte(0x01,LCD1602_data);
}
//设置光标位置,line表示第几行,row表示第几列
void LCD1602_SetXY(uint8_t line,uint8_t row)
{
    uint8_t addr;
    if(line>2 || line ==0) line = 1;
    if(row>40 || row == 0) row = 1;
    row +=0x80;
    if(line == 1)
        addr = row - 1;       //第一行
    else if(line == 2)
        addr = row - 1 + 0x40; //第二行
    LCD1602_WriteCMD(addr);
}
//********************************************************************************************
// 打印字符串程序 // (本函数调用指针函数)
//在第x行 第y列 开始显示字符串
//字符串最长48个
//********************************************************************************************/
void LCD1602_PrintString(uint8_t x,uint8_t y,char *str){
    LCD1602_SetXY(x,y);
    while(*str != 0){
        LCD1602_WriteData(*str++);
    }
}
//********************************************************************************************
// 打印单字符程序 //
//在第x行 第y列 显示字符
//* *******************************************************************************************/
void LCD1602_PrintChar(uint8_t x,uint8_t y,char t){
        LCD1602_SetXY(x,y);
        LCD1602_WriteData(t);
}
//********************************************************************************************
// LCD初始化 //(使用者可自定义,加 * 号程序行必须保留但可修改)
//********************************************************************************************/
void LCD1602_Init(void){
    #if (LCD1602_BUS_NUM == 8) //8位总线
        LCD1602_WriteCMD(0x38); // 8总线,显示2行,每个字符为5*7个像素
    #elif (LCD1602_BUS_NUM == 4) //4位总线
        LCD1602_WriteCMD(0x28); // 4总线,显示2行,每个字符为5*7个像素
        //需要设置两次
        LCD1602_WriteCMD(0x28); // 4总线,显示2行,每个字符为5*7个像素
    #endif      
    LCD1602_WriteCMD(0x01); //  显示清屏
    LCD1602_WriteCMD(0x02);     // 数据指针指向第1行第1个字符位置
    LCD1602_WriteCMD(0x06);     //  显示光标移动设置:文字不动,光标右移
    LCD1602_WriteCMD(0x0c);     //  显示开及光标设置:显示开,光标开,闪烁开
}
int main(void)
{
    SYS_Init();
    PWMA_Init();
    LCD1602_Init();
    LCD1602_PrintString(1,3,"QQ:48469646");
    LCD1602_PrintString(2,1,"BUS:4");
    LCD1602_PrintChar(2,7,'O');
    LCD1602_PrintChar(2,8,'K');
    LCD1602_PrintChar(2,9,33);   //叹号
    while(1)
    {
    }
}


使用特权

评论回复
7
zhuotuzi| | 2016-7-27 10:17 | 只看该作者
问了问高手,他们建议用CMSIS,因为更简单方便。我两个都装上了。

使用特权

评论回复
8
yiyigirl2014| | 2016-7-27 19:14 | 只看该作者
非常棒的教程,讲解的很清楚。

使用特权

评论回复
9
Harvard| | 2016-7-28 17:37 | 只看该作者
楼主啥情况 感觉是这么好的帖子压箱底了很久啊 . 库是两年前的 .单片机也是两年前的.  现在都流行M0516LDN  库也是升级到 3.x了

使用特权

评论回复
10
稳稳の幸福| | 2016-7-28 21:52 | 只看该作者
串口
我给你补上


在写串口程序之前先把硬件连接好。准备一个USB转TTL的模块(我用的是STC的下载器),他可以把M051发送的数据传送到计算机上,通过串口助手程序接收数据。USB转TTL模块的TXD接P3.0,RXD接P3.1,GND接M051的GND(也就是共地)。安装12M晶振和30pf电容。如下图所示。

MDK中也要做如下设置。从M051SeriesBSP_CMSIS_v2.01.002 里找到cor_cm0.c 、 system_M051Series.c 、 retarget.c 三个文件,加入到项目中,如下图示。


includle paths 里面也要多包含两个路径:
C:KeilM051SeriesBSP_CMSIS_v2.01.002M051SeriesBSP_CMSIS_v2.01.002LibM051SeriesCMSISCM0CoreSupport
C:KeilM051SeriesBSP_CMSIS_v2.01.002M051SeriesBSP_CMSIS_v2.01.002LibM051SeriesStdDriverinc

源文件如下:

#include
#include
#define PLLCON_SETTING      SYSCLK_PLLCON_50MHz_XTAL
#define PLL_CLOCK           50000000
void SystemInit(void)
{}
void SYS_Init(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init System Clock                                                                                       */
/*---------------------------------------------------------------------------------------------------------*/
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Enable External XTAL (4~24 MHz) */
    SYSCLK->PWRCON |= SYSCLK_PWRCON_XTL12M_EN_Msk;

    /* Waiting for 12MHz clock ready */
    SYS_WaitingForClockReady( SYSCLK_CLKSTATUS_XTL12M_STB_Msk);

    /* Switch HCLK clock source to XTAL */
    SYSCLK->CLKSEL0 = SYSCLK_CLKSEL0_HCLK_XTAL;

    /* Set PLL to power down mode and PLL_STB bit in CLKSTATUS register will be cleared by hardware.*/
    SYSCLK->PLLCON|= SYSCLK_PLLCON_PD_Msk;

    /* Set PLL frequency */        
    SYSCLK->PLLCON = PLLCON_SETTING;

    /* Waiting for clock ready */
    SYS_WaitingForClockReady(SYSCLK_CLKSTATUS_PLL_STB_Msk);

    /* Switch HCLK clock source to PLL */
    SYSCLK->CLKSEL0 = SYSCLK_CLKSEL0_HCLK_PLL;

    /* Enable IP clock */        
    SYSCLK->APBCLK = SYSCLK_APBCLK_UART0_EN_Msk | SYSCLK_APBCLK_UART1_EN_Msk;

    /* Select IP clock source */
    SYSCLK->CLKSEL1 = SYSCLK_CLKSEL1_UART_XTAL;;

    /* Reset PWMB channel0~channel3 */                    
    SYS->IPRSTC2 = SYS_IPRSTC2_PWM47_RST_Msk;                    
    SYS->IPRSTC2 = 0;      


    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */
    //SystemCoreClockUpdate();
    PllClock        = PLL_CLOCK;            // PLL
    SystemCoreClock = PLL_CLOCK / 1;        // HCLK
    CyclesPerUs     = PLL_CLOCK / 1000000;  // For SYS_SysTickDelay()

/*---------------------------------------------------------------------------------------------------------*/
/* Init I/O Multi-function                                                                                 */
/*---------------------------------------------------------------------------------------------------------*/
    /* Set P3 multi-function pins for UART0 RXD and TXD  */
    SYS->P3_MFP = SYS_MFP_P30_RXD0 | SYS_MFP_P31_TXD0;

    /* Lock protected registers */
    SYS_LockReg();
}

void UART0_Init()
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init UART                                                                                               */
/*---------------------------------------------------------------------------------------------------------*/
    UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_DIV_MODE2(__XTAL,115200);

    _UART_SET_DATA_FORMAT(UART0, UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1);
}


int main(void)
{
    uint32_t u32Item;
    SYS_Init();
    UART0_Init();
    printf("请发送一个字符");
    while(1)
    {
        u32Item = getchar();
        printf("你发送的是:%c",u32Item);
    }
}

使用特权

评论回复
11
稳稳の幸福| | 2016-7-28 21:53 | 只看该作者
烧写程序,并连接串口助手(我用的是STC的烧写工具里的串口助手),助手的波特率必须设置115200,因为M051的程序里设置的是115200。随便发送几个字母测试。

使用特权

评论回复
12
稳稳の幸福| | 2016-7-28 21:56 | 只看该作者
新唐M051看门狗使用注意事项
1、不能够在中断函数中喂狗,因为即使程序跑飞了,中断模块和中断函数依然能够正常运行,如果在中断函数里面喂狗,即使跑飞,也有可能因为在中断函数(比如定时器中断)中喂了狗而不产生复位信号,因为外设的运行有时可以独立于程序。
2、喂狗之前记得要对寄存器进行解锁操作unlock,喂狗之后要进行加锁lock。
3、关于看门狗寄存器的所有操作都要有解锁(unlock)的操作,为了方便区分起见,最好对看门狗初始化之前就要解锁(unlock),初始化后加锁(lock)。关于看门狗的中断函数也要做同样的操作,先解锁(unlock),然后清除相关标志位,保证操作有效。
4、在主程序的每一个处理流程都要适当添加一些喂狗指令
5、对于长延迟的函数,要注意喂狗方式,假如你在进行某个操作1.8秒,如下图,全局变量countMs是在Timer0定时器1ms的中断函数中进行自加,在主函数中用查询方式来确认是否大概达到你要求的时间,以下是每50ms喂狗一次,因为在看门狗初始化时,看门狗定时器是102.4ms溢出一次。

使用特权

评论回复
13
稳稳の幸福| | 2016-7-28 21:57 | 只看该作者
在新唐(nuvoton)Cortex M0上实现12864液晶屏显示
一、硬件配置
配置12864液晶的电路非常简单,市场上的通用12864液晶屏具有20个引脚,其每个引脚的功能说明如下表。


这里有几个要注意的地方:
3脚、16脚、18脚不用管它,悬空;
RS做数据/指令选择位,RS=1表示输入数据,RS=0表示数据指令;
R/W 读写控制位,高电平为读数据,低电平为写数据;
E 使能端,高电平有效
PSB 串/并模式选择 高电平为并行模式,低电平为串行模式
RST 复位位 低电平有效
DB[0..7] 数据位
下面是液晶接口电路原理图:




P2.0口做RS
P2.1口做R/W
P2.2口做E
P0口的0-7位做数据或指令输入口
P2.3口做PSB
P2.4口不用
P2.5口做复位位RST
另:图上的JPBG是接背光选择的,电阻是用来控制背光大小。

使用特权

评论回复
14
稳稳の幸福| | 2016-7-28 21:58 | 只看该作者
在新唐(nuvoton)Cortex M0上实现12864液晶屏显示
一、硬件配置
配置12864液晶的电路非常简单,市场上的通用12864液晶屏具有20个引脚,其每个引脚的功能说明如下表。


这里有几个要注意的地方:
3脚、16脚、18脚不用管它,悬空;
RS做数据/指令选择位,RS=1表示输入数据,RS=0表示数据指令;
R/W 读写控制位,高电平为读数据,低电平为写数据;
E 使能端,高电平有效
PSB 串/并模式选择 高电平为并行模式,低电平为串行模式
RST 复位位 低电平有效
DB[0..7] 数据位
下面是液晶接口电路原理图:




P2.0口做RS
P2.1口做R/W
P2.2口做E
P0口的0-7位做数据或指令输入口
P2.3口做PSB
P2.4口不用
P2.5口做复位位RST
另:图上的JPBG是接背光选择的,电阻是用来控制背光大小。

4913640366731.jpg (139.84 KB )

4913640366731.jpg

4913640340858.jpg (110.6 KB )

4913640340858.jpg

4913640366731.jpg (139.84 KB )

4913640366731.jpg

4913640340858.jpg (110.6 KB )

4913640340858.jpg

使用特权

评论回复
15
稳稳の幸福| | 2016-7-28 22:31 | 只看该作者
二、程序设计
要注意的是ARM系列微控制器GPIO口在使用时的问题,特别要注意每次输出0和输出1,使用的都是不同的寄存器。而且,GPIO口的功能每次也都需要设定它是做输入,输出还是做准双向口或者开漏模式。这一点很重要,与单片机不同,所以如果这里编程时序不注意会导致失败。
编程过程中,我使用了符合CMSIS标准的ARM Cortex微控制器标准API函数库来调用GPIO口操作函数,主要用到的有:
(1)DrvGPIO_Open
Prototype
      void DrvGPIO_Open ( E_DRVGPIO_PORT  port, E_DRVGPIO_PIN  pin, E_DRVGPIO_IO  IOMode )                Description
      Set the specified GPIO pin to the specified GPIO operation mode.
Parameter
      port [in]   E_DRVGPIO_PORT, specify GPIO port.   
It could be E_PORT0, E_PORT1, E_PORT2, E_PORT3 and E_PORT4.
      pin [in]
Specify pin of the GPIO port. It could be E_PIN0, E_PIN2 ... ~ E_PIN7.
      IOMode [in]
          E_DRVGPIO_IO, set the specified GPIO pin to be E_IO_INPUT, E_IO_OUTPUT, E_IO_OPENDRAIN or E_IO_QUASI mode.
Include
  Driver/DrvGPIO.h
Return Value
    None
Example:
   
  DrvGPIO_Open (E_PORT0, E_PIN0, E_IO_OUTPUT);
  DrvGPIO_Open (E_PORT0, E_PIN1, E_IO_INPUT);

(2)DrvGPIO_SetBit
Prototype
      int32_t DrvGPIO_SetBit (E_DRVGPIO_PORT port, E_DRVGPIO_PIN pin)
Description
     Set the specified GPIO pin to 1.
Parameter
      port [in]   
  E_DRVGPIO_PORT, specify GPIO port.   
       It could be E_PORT0, E_PORT1, E_PORT2, E_PORT3 and E_PORT4.
      pin [in]
        Specify pin of the GPIO port. It could be E_PIN0, E_PIN2 ... ~ E_PIN7.
Include
  Driver/DrvGPIO.h
Return Value
  E_SUCCESS:   Operation successful
Example:   
   
  DrvGPIO_Open (E_PORT0, E_PIN0, E_IO_OUTPUT);
   
  DrvGPIO_SetBit (E_PORT0, E_PIN0);

(3)DrvGPIO_ClrBit
Prototype
      int32_t DrvGPIO_ClrBit (E_DRVGPIO_PORT port, E_DRVGPIO_PIN pin)
Description
  Set the specified GPIO pin to 0.
Parameter     
      port [in]   
  E_DRVGPIO_PORT, specify GPIO port.   
       It could be E_PORT0, E_PORT1, E_PORT2, E_PORT3 and E_PORT4.
      pin [in]
        Specify pin of the GPIO port. It could be E_PIN0, E_PIN2 ... ~ E_PIN7.
Include
  Driver/DrvGPIO.h
Return Value
  E_SUCCESS:            Operation successful
Example:   
   
  DrvGPIO_Open (E_PORT0, E_PIN0, E_IO_OUTPUT);
   
  DrvGPIO_ClrBit (E_PORT0, E_PIN0);

(4)DrvGPIO_SetPortBits
Prototype
      int32_tDrvGPIO_SetPortBits (E_DRVGPIO_PORT port, int32_t i32PortValue)
Description
      Set the output port value to the specified GPIO port.
Parameter
      port [in]   
    E_DRVGPIO_PORT, specify GPIO port.   
       It could be E_PORT0, E_PORT1, E_PORT2, E_PORT3 and E_PORT4.
  i32PortValue [in]
  The data output value. It could be 0~0xFF.
Include
  Driver/DrvGPIO.h
Return Value
  E_SUCCESS:            Operation successful
Example:
     
    DrvGPIO_SetPortBits (E_PORT0, 0x12);

看到了上面介绍的这些库函数,就可以开始看12864的指令集了,下面把指令集附在后面

使用特权

评论回复
16
稳稳の幸福| | 2016-7-28 22:34 | 只看该作者
三、程序代码
lcd.c

//延时子程序模块
//**********************************************
void longdelay(uint32_t delay) //长延时程序延时 n*100ms
{ uint32_t i;
  for(;delay>0;delay--)
    {for(i=0;i<100;i++) //100ms延时.
        DrvSYS_Delay (1000); //调用库函数,延时n us
    }
}

void shortdelay(uint32_t dly) //短延时程序 nms
{
for(;dly>0;dly--)
DrvSYS_Delay(1000);
}

//**********************************
//液晶初始化
//**********************************
void init_lcd(void)
{ uint8_t comm;
shortdelay(3);
comm=0x01; //清除显示
wr_i_lcd(comm);
shortdelay(3);
comm=0x30; //普通指令集格式
wr_i_lcd(comm);
shortdelay(3);
comm=0x06; //光标右移
wr_i_lcd(comm);
shortdelay(3);
comm=0x02; //地址归位
wr_i_lcd(comm);
shortdelay(3);
comm=0x06; //整体不移动
wr_i_lcd(comm);
shortdelay(3);
comm=0x0c; //整体显示,不反白
wr_i_lcd(comm);
shortdelay(3);
comm=0x01; //复位
wr_i_lcd(comm);
shortdelay(3);
comm=0x80; //设定DDRAM起始为0x80
wr_i_lcd(comm);
shortdelay(3);
}
//***********************************
//填充液晶DDRAM全为空格
//**********************************
void clrram_lcd(void)
{ uint16_t data;
data=0x30;
wr_i_lcd(data);
shortdelay(3);
data=0x01;
wr_i_lcd(data);
longdelay(2);
}
//***********************************
//对液晶写数据
//content为要写入的数据
//***********************************
void wr_d_lcd(uint8_t content)
{
busy_lcd();
DrvGPIO_Open(E_PORT2, E_PIN0, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT2, E_PIN1, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT2, E_PIN2, E_IO_OUTPUT);
DrvGPIO_SetBit(E_PORT2, E_PIN0); //rs=1,data mode
    DrvGPIO_ClrBit(E_PORT2, E_PIN1); //rw=0,write mode

DrvGPIO_Open(E_PORT0, E_PIN0, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN1, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN2, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN3, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN4, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN5, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN6, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN7, E_IO_OUTPUT);

DrvGPIO_SetPortBits(E_PORT0,content); //write data

DrvGPIO_SetBit(E_PORT2, E_PIN2); //enable
shortdelay(2);
DrvGPIO_ClrBit(E_PORT2, E_PIN2); //disable
}
//********************************
//对液晶写指令
//content为要写入的指令代码
//*****************************
void wr_i_lcd(uint8_t content)
{
busy_lcd();
DrvGPIO_Open(E_PORT2, E_PIN0, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT2, E_PIN1, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT2, E_PIN2, E_IO_OUTPUT);
DrvGPIO_ClrBit(E_PORT2, E_PIN0); //rs=0,command mode
    DrvGPIO_ClrBit(E_PORT2, E_PIN1); //rw=0,write mode

DrvGPIO_Open(E_PORT0, E_PIN0, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN1, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN2, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN3, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN4, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN5, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN6, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN7, E_IO_OUTPUT);

DrvGPIO_SetPortBits(E_PORT0,content); //write command

DrvGPIO_SetBit(E_PORT2, E_PIN2); //enable
shortdelay(2);
DrvGPIO_ClrBit(E_PORT2, E_PIN2); //disable
}
//********************************
//液晶检测忙状态
//在写入之前必须执行
//********************************
void busy_lcd(void)
{
DrvGPIO_Open(E_PORT0, E_PIN0, E_IO_OUTPUT); //下面几行都为打开P0端口,设定为输出模式
DrvGPIO_Open(E_PORT0, E_PIN1, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN2, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN3, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN4, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN5, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN6, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT0, E_PIN7, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT2, E_PIN0, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT2, E_PIN1, E_IO_OUTPUT);
DrvGPIO_Open(E_PORT2, E_PIN2, E_IO_OUTPUT);
  DrvGPIO_SetPortBits(E_PORT0,0xff);
  DrvGPIO_ClrBit(E_PORT2, E_PIN0); //rs=0
  DrvGPIO_SetBit(E_PORT2, E_PIN1); //rw=1,read
  DrvGPIO_SetBit(E_PORT2, E_PIN2); //enable
DrvGPIO_Open(E_PORT0, E_PIN7, E_IO_INPUT); //set p0.7 as a input pin ==busy
  while((DrvGPIO_GetBit (E_PORT0, E_PIN7))!=0); //while is busy
  DrvGPIO_ClrBit(E_PORT2, E_PIN2); //disable
}
//********************************
//指定要显示字符的坐标
//*******************************
void gotoxy(uint8_t y,uint8_t x)
{
if(y==1)
wr_i_lcd(0x80|x); //第一行
if(y==2)
        wr_i_lcd(0x90|x); //第二行
if(y==3)
wr_i_lcd((0x80|x)+8); //第三行
if(y==4)
        wr_i_lcd((0x90|x)+8); //第四行
}
//**********************************
//液晶显示字符串程序
//**********************************
void print(uint8_t *str)
{
while(*str!='\0')
{
wr_d_lcd(*str);
str++;
}
}

//***************************************
//液晶显示主程序模块
//***************************************
void show()   
{
  
  gotoxy(1,0);
  print("南京航空航天大学");
  shortdelay(200);            
  gotoxy(2,0);
  print("计算机科学与技术");
  shortdelay(200);                 //扫描延时
  gotoxy(3,0);
  print("WWW.NUAA.EDU.CN");
  shortdelay(200);                 //扫描延时
  gotoxy(4,0);
  print("12864 液晶测试");
  shortdelay(200);                 //扫描延时
}

使用特权

评论回复
17
dongliushui| | 2018-4-28 17:44 | 只看该作者
这个系列确实很牛X,而且比STM32的好入门。

使用特权

评论回复
18
643757107| | 2018-4-29 09:34 | 只看该作者
最优秀的入门单片机。s

使用特权

评论回复
19
xixi2017| | 2018-4-29 19:12 | 只看该作者
入门学习的帮手。

使用特权

评论回复
20
huahuagg| | 2020-2-17 22:18 | 只看该作者
好贴,MARK。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

188

主题

3241

帖子

10

粉丝