STM32 定时器产生PWM彻底应用

发布者:kappa20最新更新时间:2016-10-08 来源: eefocus关键字:STM32  定时器  PWM 手机看文章 扫描二维码
随时随地手机看文章
这次学习STM32花了很长时间,一个礼拜多,也有颇多收获,学习过程也有颇多曲折。这次的任务是:用STM32的一个定时器在四个通道上产生四路频率可调占空比可调的PWM波。

看到这个题,我先看STM32的数据手册,把STM32的定时器手册看完就花了一天,但是看了一遍任然不知道所云,就看库函数,略有点理解,就想一哈把这个程序调出来,于是就花了一天多时间仿照网上别人的程序来写,花了一天多写出来调试,结果行不通,做了无用功,于是静下心来想想,还是一步一步的来。

我先用STM32的通用定时器用PWM模式产生四路相同占空比,不同频率的PWM波,配置如下:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//使能TIM2时钟

       TIM_InternalClockConfig(TIM2);//使用内部时钟

 

       TIM_BaseInitStructure.TIM_Prescaler=3; //设置TIM时钟频率除数的预分频值

      TIM_BaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//选择计数器模式

      TIM_BaseInitStructure.TIM_Period=1799;//设置下一个更新事件装入活动的自动重装载寄存器周期的值

      TIM_BaseInitStructure.TIM_ClockDivision=0;//设置时钟分割

 

       TIM_TimeBaseInit(TIM2,&TIM_BaseInitStructure);

      

       //通道1

       TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//选择定时器模式

      TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//选择输出比较状态

      TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Disable;//选择互补输出比较状态

      TIM_OCInitStructure.TIM_Pulse=CCR1_Val;//设置了待装入捕获比较器的脉冲值

      TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//设置输出极性

      TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low;//设置互补输出极性

      TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Set;//选择空闲状态下得非工作状态

      TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Reset;//选择互补空闲状态下得非工作状态

       TIM_OC1Init(TIM2,&TIM_OCInitStructure);

       TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);

 

       //通道2  

      TIM_OCInitStructure.TIM_Pulse=CCR2_Val;//设置了待装入捕获比较器的脉冲值

       TIM_OC2Init(TIM2,&TIM_OCInitStructure);

       TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable);

 

       //通道3

       TIM_OCInitStructure.TIM_Pulse=CCR3_Val;//设置了待装入捕获比较器的脉冲值

       TIM_OC3Init(TIM2,&TIM_OCInitStructure);

       TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Enable);

 

       //通道4

       TIM_OCInitStructure.TIM_Pulse=CCR4_Val;//设置了待装入捕获比较器的脉冲值

       TIM_OC4Init(TIM2,&TIM_OCInitStructure);

       TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Enable);

 

       TIM_Cmd(TIM2, ENABLE);

       TIM_CtrlPWMOutputs(TIM2,ENABLE);

用pwm模式输出的频率和占空比是固定的,不可调,要想输出频率可调,占空比可调,必须得使用比较输出模式。这点资料是在STM32全国巡回研讨会上看到的,如图:

 

所以,接下来我就写了一个程序通过输出比较模式产生一路PWM波,这个波的频率和占空比都由自己确定,函数配置如下:

       TIM_BaseInitStructure.TIM_Prescaler=3; //设置TIM时钟频率除数的预分频值(18M)

      TIM_BaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//选择计数器模式

      TIM_BaseInitStructure.TIM_Period=1800;//设置下一个更新事件装入活动的自动重装载寄存器周期的值

      TIM_BaseInitStructure.TIM_ClockDivision=0;//设置时钟分割

       TIM_TimeBaseInit(TIM2,&TIM_BaseInitStructure);

       //通道1

       TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;//选择定时器模式

      TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//选择输出比较状态

      TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Disable;//选择互补输出比较状态

      TIM_OCInitStructure.TIM_Pulse=CCR1_Val1;//设置了待装入捕获比较器的脉冲值

      TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//设置输出极性

      TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low;//设置互补输出极性

      TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Set;//选择空闲状态下得非工作状态

      TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Reset;//选择互补空闲状态下得非工作状态

       TIM_OC1Init(TIM2,&TIM_OCInitStructure);

       TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);

       TIM_ARRPreloadConfig(TIM2,ENABLE);

       TIM_ITConfig(TIM2,TIM_IT_CC1,ENABLE);

       TIM_Cmd(TIM2,ENABLE);

             

}

 

 

void TIM2_IRQHandler(void)

{

       TIM_ClearITPendingBit(TIM2,TIM_IT_CC1);

       if(n==1)

       {

              n=0;

              TIM_SetCompare1(TIM2,CCR1_Val2);

       }

       else

       {

              n=1;

             TIM_SetCompare1(TIM2,CCR1_Val1);

       }                                    

}

通过改变比较寄存器(CCR1)中的值,改变PWM的占空比,在每次匹配中断中改变CCR1的值。上面程序实现的是产生一路频率为10K占空比为40%的PWM波。

有了上面的思想我就想产生四路不同频率不同占空比的PWM波,经过反复思考光配函数似乎不能实现,在网上去查了的,很多网友也说不能实现,有一个网友给了一个提示:软件模拟。刚开始没明白什么意思,于是还是自己继续配置库函数,在这个过程中一直有两个疑问:

每次中断中,CCR寄存器的值都在循环的增加,CCR的寄存器不可能是无限大吧?就算是无限大,计数器也不是无限大呀,他只能记到65535。初步确定使用匹配中断不行,我有想过同时使用溢出中断和匹配中断,但这样四路PWM波只能是固定的,频率和占空比不能调。大概说一下怎样用溢出中断和匹配中断实现四路固定的PWM波,把计数器寄存器(CNT)的值装最大周期的那个PWM波,当一次计数完成算一下三路小点周期数,在匹配中断中对应的设个变量,CCR就改变几次,溢出中断来了就再次给计数器装初值,同时四个比较寄存器从装初值,这样很麻烦,理论上可以实现,但我考虑到最终不能实现我的要求,就没有去验证。所以产生四路频率可调占空比可调,用一个定时器似乎不能实现,就一直卡到这里,我又在想飞哥说能实现,就肯定能实现,我又在网上找资料,还是没找到,只是有人题四路,软模拟,于是我就思考用软模拟实现,最后在一个师兄的指点下,确实用软件模拟一个中间比较寄存器能实现,思路大概是这样子的,首先让比较寄存器装满,也就是最大值(65535),然后通过改变模拟比较寄存器的值,每次匹配中断只需把模拟比较寄存器的值去比较就行,具体方案看程序。

unsigned char  Cnt[4]; //一个数组,这个数组的每个元素对应一个通道,用来判断装PWM得高电平还是低电平数

unsigned int  T[4];//周期数组

unsigned int  R[4];//模拟的比较寄存器数组,一样的每个通道对应一个数组元素

unsigned int  Rh[4];//模拟的PWM高电平比较寄存器

unsigned int  Rl[4]; //模拟的PWM低电平比较寄存器

unsigned char F[4];//占空比数组

unsigned int CCR1,CCR2,CCR3,CCR4;

 

void Init(void)

{

       unsigned char i = 0;      

       for(i = 0; i < 4; i++)

       {

              Cnt[i]= 0;

              T[i]  = 0;

              R[i]  = 0;

              Rh[i] = 0;

              Rl[i] = 0;

              F[i]  = 0;

       }    

       //t的范围为(0~65536)    

       T[0] = 450;        //F=40K

       T[1] = 600;        //F=30K

       T[2] = 900;        //F=20K

       T[3] = 1800;   //F=10K

       //F(占空比)的范围为(0~100)

       F[0] = 40;

       F[1] = 30;

       F[2] = 20;

       F[3] = 10;     

       for(i = 0; i < 4; i++)

       {

              Rh[i] = (T[i] * F[i]) / 100;

              Rl[i] = T[i] - Rh[i];

       }    

       R[0] = Rl[0];

       R[1] = Rl[1];

       R[2] = Rl[2];

       R[3] = Rl[3];

      

       CCR1 = R[0];

       CCR2 = R[1];

       CCR3 = R[2];

       CCR4 = R[3];

}

对应的数组初始化

 

void RCC_Configuration(void)

{

       RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);

       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE);

       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);

}

时钟配置

void GPIO_Configuration(void)

{

       GPIO_InitTypeDef GPIO_InitStructure;

   //Key1 PA0 Key3 PA8

       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_8;

      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

       GPIO_Init(GPIOA,&GPIO_InitStructure);

       //Key2 PC13

       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13;

      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

       GPIO_Init(GPIOC,&GPIO_InitStructure);

       //Key PD3

       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;

      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

       GPIO_Init(GPIOD,&GPIO_InitStructure);

       //TIM3 CH1 CH2

       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;

      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

       GPIO_Init(GPIOA,&GPIO_InitStructure);

       //TIM3 CH3 CH4

       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;

      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

       GPIO_Init(GPIOB,&GPIO_InitStructure);

}

管脚配置

void NVIC_Configuration(void)

{

       NVIC_InitTypeDef NVIC_InitStructure;

       #ifdef VECT_TAB_RAM

       NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);

       #else

       NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);

       #endif

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

 

       NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQChannel;

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;

      NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;

      NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

 

       NVIC_Init(&NVIC_InitStructure);     

}

中断配置

void TIM_Configuration(void)

{

       TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;

       TIM_OCInitTypeDef TIM_OCInitStructure;

 

       TIM_InternalClockConfig(TIM3);

 

       TIM_BaseInitStructure.TIM_Prescaler=3;//4分频,18M

      TIM_BaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;

      TIM_BaseInitStructure.TIM_Period=65535;

      TIM_BaseInitStructure.TIM_ClockDivision=0;

      TIM_BaseInitStructure.TIM_RepetitionCounter=0;

       TIM_TimeBaseInit(TIM3,&TIM_BaseInitStructure);

 

       TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;

      TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;

      TIM_OCInitStructure.TIM_Pulse=CCR1;

      TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;

       TIM_OC1Init(TIM3,&TIM_OCInitStructure);

       TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Disable);

       TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);

 

       TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;

       TIM_OCInitStructure.TIM_Pulse=CCR2;

       TIM_OC2Init(TIM3,&TIM_OCInitStructure);

       TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Disable);

       TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);

 

     TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;

       TIM_OCInitStructure.TIM_Pulse=CCR3;

       TIM_OC3Init(TIM3,&TIM_OCInitStructure);

       TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Disable);

       TIM_ClearITPendingBit(TIM3,TIM_IT_CC3);

 

       TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;

       TIM_OCInitStructure.TIM_Pulse=CCR4;

       TIM_OC4Init(TIM3,&TIM_OCInitStructure);

       TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Disable);

       TIM_ClearITPendingBit(TIM3,TIM_IT_CC4);

 

       TIM_Cmd(TIM3,ENABLE);

       TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);

       TIM_ITConfig(TIM3,TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4,ENABLE);

}

 

void TIM3_IRQHandler(void)

{

       if(TIM_GetITStatus(TIM3,TIM_IT_CC1)!=RESET)

       {

              TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);

              Cnt[0]=(~Cnt[0])&0x01;

              if(Cnt[0]==0x01)  

                     R[0]+=Rl[0];

              else

                     R[0] += Rh[0];

              if(R[0]>65535)

                     R[0]=R[0]-65535;

              CCR1=R[0];

              TIM_SetCompare1(TIM3,CCR1);

       }

       if(TIM_GetITStatus(TIM3,TIM_IT_CC2)!=RESET)

       {

              TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);

              Cnt[1]=(~Cnt[1])&0x01;

              if(Cnt[1]==0x01)  

                     R[1]+=Rl[1];

              else

                     R[1] += Rh[1];

              if(R[1]>65535)

                     R[1]=R[1]-65535;

              CCR2=R[1];

              TIM_SetCompare2(TIM3,CCR2);

       }    

       if(TIM_GetITStatus(TIM3,TIM_IT_CC3)!=RESET)

       {

              TIM_ClearITPendingBit(TIM3,TIM_IT_CC3);

              Cnt[2]=(~Cnt[2])&0x01;

              if(Cnt[2]==0x01)  

                     R[2]+=Rl[2];

              else

                     R[2] += Rh[2];

              if(R[2]>65535)

                     R[2]=R[2]-65535;

              CCR3=R[2];

              TIM_SetCompare3(TIM3,CCR3);

       }    

       if(TIM_GetITStatus(TIM3,TIM_IT_CC4)!=RESET)

       {

              TIM_ClearITPendingBit(TIM3,TIM_IT_CC4);

 

              Cnt[3] = (~Cnt[3])&0x01;

             

              if(Cnt[3]==0x01)  

                     R[3]+=Rl[3];

              else

                     R[3] += Rh[3];

              if(R[3]>65535)

                     R[3]=R[3]-65535;

              CCR4=R[3];

              TIM_SetCompare4(TIM3,CCR4);                     

       }

}

中断函数

其余就是按键扫描函数,通过改变周期数组中的值和占空比寄存器中的值就能改变PWM波的频率和占空比,当然按键可以设置为4个(一个按键对应一个通道),如果IO够用也可以设置8个,没两个按键对应一个通道分别改变频率和占空比。

关键字:STM32  定时器  PWM 引用地址:STM32 定时器产生PWM彻底应用

上一篇:STM32的ADC DMA USART综合学习
下一篇:STM32复位/时钟控制

推荐阅读最新更新时间:2024-03-16 15:14

采用ARM的PWM模块的超声波检测系统的设计
   近年来以微电子学和计算机技术为基础的信息技术飞速发展,超声无损检测仪器也得到了前所未有的发展动力,为了提高检测的可靠性和提高检测效率,研制数字化、智能化、自动化、图像化的超声仪是当今无损检测领域发展的一个重要趋势。而传统的超声波检测仪存在准确性差、精度低、体积大、功耗大、人机界面不友好等问题。而超声波发射与控制电路正是在一种基于ARM的超声波检测系统的基础上,以ARM微控制器为核心,使用C语言编程,方便地实现了发射频率与激励电压脉冲幅度的调节。   1 超声波检测系统的总体设计结构   基于ARM超声波检测系统的总体结构框图,如图1所示。该系统主要由3部分组成:超声波前端发射接收电路、DSP和ARM处理器。  
[单片机]
采用ARM的<font color='red'>PWM</font>模块的超声波检测系统的设计
stm32的按键扫描[操作寄存器+库函数]
本例将实现stm32的按键扫描功能。 操作寄存器 stm32的I/O口作为输入使用时,是通过读取GPIOx - IDR 寄存器的内容来读取I/O口状态的。 IDR寄存器各位描述如下: 由于systick不能像库函数那样方便的产生中断,通过查询systick状态位后,再查询各管脚状态反而更为不方便,所以和库函数方法不一样,直接查询了管脚状态来检测按键。 代码中调用 PAout(x) 、 PAin(x)等函数 在sys.h文件中,参见:(sys.h 代码参照 stm32 直接操作寄存器开发环境配置 ) 直接操作寄存器代码: #include stm32f10x_lib.h #include system
[单片机]
<font color='red'>stm32</font>的按键扫描[操作寄存器+库函数]
STM32HAL库移植中景园库函数代码
为电赛做准备,随手练习移库,在监测电压的基础上,移植中景园的库到 hal库 里面 视频参考这个: 0xA1-OLED-STM32CubeMx配置 I2C并移植OLED驱动程序(基于ssd1306) 说的特别棒! 没基础看这个: 单片机stm32第14课(跨单片机移植tm1638程序) 下面是我移植前面的代码(固件库): main.c: // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //中景园电子 //店铺地址:http://shop73023976.taobao.com/?spm=2013.1.0.0.M4PqC2 // // 文 件 名 : main.c // 版 本 号 :
[单片机]
STM32HAL库移植中景园库函数代码
STM32 HAL库与标准库的区别
前言   相比较早几年使用标准库开发来讲,最近几年HAL库的使用是越来越多,那么我们开发应当使用哪一种呢,本文着重介绍常用的几种开发方式及相互之间的区别,白猫也好、黑猫也好,抓到耗子就是好猫。 STM32三种开发方式   通常新手在入门STM32的时候,首先都要先选择一种要用的开发方式,不同的开发方式会导致你编程的架构是完全不一样的。一般大多数都会选用标准库和HAL库,而极少部分人会通过直接配置寄存器进行开发。   网上关于标准库、HAL库的描述相信是数不胜数。可是一个对于很多刚入门的朋友还是没法很直观的去真正了解这些不同开发发方式彼此之间的区别,所以笔者想以一种非常直白的方式,用自己的理解去将这些东西表述出来,如果有描
[单片机]
<font color='red'>STM32</font> HAL库与标准库的区别
STM32基于固件库学习笔记(11)RTC实时时钟
实时时钟(RTC) 小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F101xx、STM32F102xx和STM32F103xx微控制器。 中容量产品是指闪存存储器容量在64K至128K字节之间的STM32F101xx、STM32F102xx和STM32F103xx微控制器。 大容量产品是指闪存存储器容量在256K至512K字节之间的STM32F101xx和STM32F103xx微控制器。 互联型产品是指STM32F105xx和STM32F107xx微控制器。 主要特性 ● 可编程的预分频系数:分频系数最高为20 。 ● 32位的可编程计数器,可用于较长时间段的测量。 ● 2个分离的时钟:用于APB1接口的PC
[单片机]
C语言使用定时器的方法控制LED灯以1S的速度闪亮
最近因为赶不上提高班的进度,老师给的教程总是断断续续的,所以我打算跟11月1号通过考试的网友们一起学习,呵呵,这也是我一教训来着,在三维里学习要坚持一步一个脚印,坚持必有奇迹,但也要跟得上大家,以后再忙也要努力实现计划了,不能再像这次一样,因为所谓的考试落下了好几堂课,不过也没有关系,能够吸取点教训总是好的。我可以先给自己点时间多学些其它的基础知识。 今天开始学单片机的计数器了,呵呵,可能是一直因为用C语言编程序我定时老是定不准的原因,当得知学会定时/计数器后可以让单片机C语言定时准确后,我感觉学它真的很有动力,虽然编一个简单的程序也花了我好长时间,但编出来的感觉却是那么的爽快,我觉得要学会定时/计数器,关键是要学会编程控制 TCO
[单片机]
基于stm32的电子秤方案
  什么是电子秤   电子秤(英文名:electronic balance)是衡器的一种,是利用胡克定律或力的杠杆平衡原理测定物体质量的工具。按结构原理可分为机械秤、电子秤、机电结合秤三大类。   电子秤主要由承重系统(如秤盘、秤体)、传力转换系统(如杠杆传力系统、传感器)和示值系统(如刻度盘、电子显示仪表)3部分组成。      基于stm32的电子秤方案大全(一)   基于STM32的多功能电子秤设计   题目要求:   1、基本部分:   (1)能用键盘设置单价,称重后能同时显示重量、单价和总额;电子计价秤:最大称重为10.000公斤,重量误差不大于±0.1%;   (2)具有TFT液晶屏显示,显示重量、单价、总额等信息
[单片机]
基于<font color='red'>stm32</font>的电子秤方案
STM32单片机对TFTLCD的驱动设计
看了TFTLCD和FSMC(灵活的静态存储控制器)的简介,还是一知半解,不知所云。 TFTLCD使用80并口,80 并口有如下一些信号线: CS: TFTLCD 片选信号。 WR:向 TFTLCD 写入数据。 RD:从 TFTLCD 读取数据。 D[15: 0]: 16 位双向数据线。 RST:硬复位 TFTLCD。 RS:命令/数据标志( 0,读写命令; 1,读写数据)。 只是记住FSMC在使用的时候要初始化和使能就行了。 关于lcd.c这个文件竟然接近3000行,好吧,我是写不出来,只能在主函数里调用了。 main.c: intmain(void) { u8x=0; u8lcd_id[12];//存放LCDID字符串
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved