PWM控制输出代码
51系列单片机输出PWM的两种方法

51系列单片机输出PWM的两种方法PWM(Pulse Width Modulation,脉宽调制)是一种常用的调制技术,通过改变信号的脉宽来控制输出电平的占空比。
在51系列的单片机中,常用的PWM输出方式有基于定时/计数器和软件实现两种方法。
一、基于定时/计数器的PWM输出方法:在51系列单片机中,内部有多个定时/计数器可用于实现PWM输出。
这些定时/计数器包括可编程定时/计数器T0、T1、T2和看门狗定时器。
1.T0定时/计数器:T0定时/计数器是最简单和最常用的PWM输出方式之一、通过配置T0定时/计数器的工作模式和重装值来实现PWM输出。
具体步骤如下:(1)选择T0的工作模式:将定时/计数器T0设置为工作在16位定时器模式,并使能PWM输出。
(2)设置T0的重装值:通过设定T0的装载值来定义PWM输出的周期。
(3)设置T0的计数初值:通过设定T0的计数初值来定义PWM输出的脉宽。
(4)启动T0定时/计数器:开启T0定时/计数器的时钟源,使其开始计数。
2.T1定时/计数器:T1定时/计数器相对于T0定时/计数器来说更加灵活,它具有更多的工作模式和功能,可以实现更复杂的PWM输出。
与T0定时/计数器类似,通过配置T1的工作模式、装载值和计数初值来实现PWM输出。
3.T2定时/计数器:T2定时/计数器在51系列单片机中的应用较少,但也可以用于实现PWM输出。
与T0和T1不同,T2定时/计数器没有独立的PWM输出功能,需要结合外部中断请求(INT)来实现PWM输出。
二、软件实现PWM输出方法:在51系列单片机中,除了利用定时/计数器来实现PWM输出外,还可以通过软件来实现PWM输出。
软件实现PWM的核心思想是利用延时控制来生成不同占空比的方波信号。
软件实现PWM输出的步骤如下:(1)设置IO口:选择一个适合的IO口,将其设置为输出模式。
(2)生成PWM信号:根据要求的PWM占空比,通过控制IO口的高低电平和延时的时间来生成PWM方波信号。
正弦波脉宽调制代码

正弦波脉宽调制代码下面是一个使用Python编程语言编写的正弦波脉宽调制(PWM)的示例代码:python.import numpy as np.import matplotlib.pyplot as plt.# 生成正弦波。
t = np.linspace(0, 1, 500, endpoint=True) # 时间从0到1秒,共500个点。
f = 5 # 正弦波的频率为5Hz.x = np.sin(2 np.pi f t) # 生成正弦波信号。
# 脉宽调制。
duty_cycle = 0.5 # 占空比为50%。
pwm = np.zeros_like(t)。
pwm[x > 0] = 1 # 正半周部分为1,负半周部分为0。
# 绘制图形。
plt.figure()。
plt.subplot(2, 1, 1)。
plt.plot(t, x, 'b')。
plt.title('Sinewave')。
plt.subplot(2, 1, 2)。
plt.plot(t, pwm, 'r')。
plt.title('PWM Signal')。
plt.show()。
这段代码首先使用NumPy库生成了一个5Hz频率的正弦波信号,然后通过脉宽调制技术将正弦波转换为PWM信号。
在这个示例中,占空比设为50%,即正半周为高电平,负半周为低电平。
最后,使用Matplotlib库将原始正弦波和PWM信号绘制在同一张图上进行对比。
需要注意的是,这只是一个简单的示例代码,实际的PWM调制可能涉及到更复杂的信号处理和控制逻辑,具体实现会根据具体的应用场景和要求而有所不同。
stm32输出pwm占空比代码

stm32输出pwm占空比代码在STM32单片机中,输出PWM(脉冲宽度调制)信号是非常普遍的操作,这种信号通常用于控制电机、LED灯等电子设备的亮度或运动状态。
本文将详细介绍STM32单片机如何输出PWM占空比代码。
一、配置TIM定时器要输出PWM信号,首先需要进行TIM定时器的配置。
在KEIL C 编译器中,可以通过CubeMX插件进行配置。
在此之前需要先引入库文件“stm32fxx_hal_tim.h”。
在CubeMX中选择对应的TIM,进入“Mode”选项卡,将TIM定时器配置为PWM输出模式。
在“Configuration”选项卡中,配置TIM的时钟源和预分频系数等信息。
此外还需要配置PWM的周期和占空比,具体可以通过下面的步骤实现。
二、设置PWM周期在代码中设置PWM周期,可以使用HAL库中的“__HAL_TIM_SET_AUTORELOAD”函数。
该函数的第一个参数为TIM定时器的句柄,第二个参数为PWM的周期,单位为计数器的值。
可以根据需要调整该值来改变PWM的输出频率。
例如,将PWM周期设置为1000,代码如下:__HAL_TIM_SET_AUTORELOAD(&htim1, 1000);三、设置PWM占空比在代码中设置PWM占空比,需要使用HAL库中的“__HAL_TIM_SET_COMPARE”函数。
该函数的第一个参数是TIM定时器的句柄,第二个参数是设置输出PWM的通道,第三个参数是占空比。
占空比的取值范围为0到PWM周期。
例如,将PWM占空比设置为500,代码如下:__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 500);四、使用PWM输出信号最后,在代码中使用PWM输出信号,可以使用HAL库中的“HAL_TIM_PWM_Start”函数。
该函数的参数为TIM的句柄和输出PWM 的通道。
例如,在TIM1通道1上启动PWM输出,代码如下:HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);以上就是STM32单片机输出PWM占空比代码的详细步骤。
6路PWM输出协议和接线图

PWM通讯协议PC机、单片机、PLC(统称上位机)通过 2 3 2 或485发数据:串口通讯参数默认设置:波特率9600,8位数据位,1位停止位,无校验。
每条指令的CRC校验码可以用16进制的AA AA 代替。
1-1、输出一路PWM(单独输出每一路PWM的频率和占空比,PWM1,PWM2、PWM3、PWM4这4路是独立的频率和占空比;PWM5、PWM6和PWM1这3路的频率是一样,更改任一个频率,其他2个的频率一起更改,占空比可以不一样)上位机发送代码:21 10 22 51 00 02 04 00 27 10 32 20 20➢ 21 : 站号(RS485地址)➢ 10 : 功能码,写多个寄存器➢ 22 51: 第一路寄存器地址22 52: 第二路寄存器地址22 53: 第三路寄存器地址22 54: 第四路寄存器地址22 55: 第五路寄存器地址22 56: 第六路寄存器地址➢ 00 02: 寄存器个数➢ 04 : 数据个数(字节数)➢ 00 27 10 :第一路(第三路)PWM的频率(16进制002710的10进制是10000即10K频率)➢ 32:第一路(第三路)PWM的高电平时间占PWM周期的比例(16进制32的10进制是50即输出高电平的时间是PWM周期的一半50%)➢ 20 20:二个字节CRC码此命令将输出“第一路PWM频率10K,高电平占空比50%;设备返回:21 10 22 51 00 02 04 C0 CA一、输出4路PWM(PWM1-PWM2是独立控制的,PWM3和PWM1是一样的,PWM4和PWM2是一样的)上位机发送代码:21 10 12 46 00 04 0800 27 10 32 00 4E 20 14 B3 09➢ 21 : 站号(RS485地址)➢ 10 : 功能码,写多个寄存器➢ 12 46: 寄存器地址➢ 00 04: 寄存器个数➢ 08 : 数据个数(字节数)➢ 00 27 10 :第一路(第三路)PWM的频率(16进制002710的10进制是10000即10K频率)➢ 32:第一路(第三路)PWM的高电平时间占PWM周期的比例(16进制32的10进制是50即输出高电平的时间是PWM周期的一半50%)➢ 00 4E 20 :第二路(第四路)PWM的频率(16进制004E20的10进制是20000即20K频率)➢ 14:第二路(第四路)PWM的高电平时间占PWM周期的比例(16进制14的10进制是20即输出高电平的时间是PWM周期的20%)➢ B3 09:二个字节CRC码此命令将输出“第一路(第三路)PWM频率10K,高电平占空比50%;第二路(第四路)PWM频率20K,高电平占空比20%”设备返回:21 10 12 46 00 04 08 86 DF二、输出4路PWM(PWM1-PWM4是独立控制的)上位机发送代码:21 10 12 46 00 08 1000 27 10 3200 4E 20 14 00 03 E8 32 00 07 D0 14 AA AA➢ 21 : 站号(RS485地址)➢ 10 : 功能码,写多个寄存器➢ 12 46: 寄存器地址➢ 00 08: 寄存器个数➢ 10 : 数据个数(字节数)➢ 00 27 10 :第一路PWM的频率(16进制002710的10进制是10000即10K频率)➢ 32:第一路PWM的高电平时间占PWM周期的比例(16进制32的10进制是50即输出高电平的时间是PWM周期的一半50%)➢ 00 4E 20 :第二路PWM的频率(16进制004E20的10进制是20000即20K频率)➢ 14:第二路PWM的高电平时间占PWM周期的比例(16进制14的10进制是20即输出高电平的时间是PWM周期的20%)➢ 00 03 E8 :第三路PWM的频率(16进制0003E8的10进制是1000即1K频率)➢ 32:第三路PWM的高电平时间占PWM周期的比例(16进制32的10进制是50即输出高电平的时间是PWM周期的50%)➢ 00 07 D0 :第四路PWM的频率(16进制0007D0的10进制是2000即2K频率)➢ 14:第四路PWM的高电平时间占PWM周期的比例(16进制14的10进制是20即输出高电平的时间是PWM周期的20%)➢ AA AA:二个字节固定码此命令将输出“第一路PWM频率10K,高电平占空比50%;第二路PWM 频率20K,高电平占空比20%;第三路PWM频率1K,高电平占空比50%;第四路PWM频率2K,高电平占空比20%”设备返回:21 10 12 46 00 08 10 83 D5三、输出6路PWM上位机发送代码:21 10 12 46 00 09 1200 27 10 3200 4E 20 14 00 03 E8 32 00 07 D0 14 30 20 AA AA➢ 21 : 站号(RS485地址)➢ 10 : 功能码,写多个寄存器➢ 12 46: 寄存器地址➢ 00 09: 寄存器个数➢ 12 : 数据个数(字节数)➢ 00 27 10 :第一路PWM的频率(16进制002710的10进制是10000即10K频率)➢ 32:第一路PWM的高电平时间占PWM周期的比例(16进制32的10进制是50即输出高电平的时间是PWM周期的一半50%)➢ 00 4E 20 :第二路PWM的频率(16进制004E20的10进制是20000即20K频率)➢ 14:第二路PWM的高电平时间占PWM周期的比例(16进制14的10进制是20即输出高电平的时间是PWM周期的20%)➢ 00 03 E8 :第三路PWM的频率(16进制0003E8的10进制是1000即1K频率)➢ 32:第三路PWM的高电平时间占PWM周期的比例(16进制32的10进制是50即输出高电平的时间是PWM周期的50%)➢ 00 07 D0 :第四路PWM的频率(16进制0007D0的10进制是2000即2K频率)➢ 14:第四路PWM的高电平时间占PWM周期的比例(16进制14的10进制是20即输出高电平的时间是PWM周期的20%)➢ 30:第五路PWM的高电平时间占PWM周期的比例(16进制30的10进制是48即输出高电平的时间是PWM周期的48%)➢ 20:第六路PWM的高电平时间占PWM周期的比例(16进制20的10进制是32即输出高电平的时间是PWM周期的32%)第5路和第六路的PWM频率和第一路的PWM频率是一样的,占空比不一样。
STM32使用HAL库输出连续可调的PWM信号

STM32使用HAL库输出连续可调的PWM信号1.配置GPIO引脚作为PWM输出。
选择一个合适的GPIO引脚,并将其配置为复用模式,用于PWM输出。
例如,若使用TIM1作为PWM输出定时器,则可以选择GPIO引脚PA8,其复用功能为TIM1_CH12.配置定时器。
使用HAL库初始化和配置所选定的定时器(例如TIM1)作为PWM输出的时基。
设置定时器的时钟源、预分频因子和计数周期。
可以通过修改这些参数来调整PWM信号的频率。
3.配置PWM输出通道。
使用HAL库初始化和配置所选定的PWM输出通道(例如TIM1_CH1)。
设置通道的输出模式和占空比。
可以通过修改占空比来调整PWM信号的高电平时间,从而改变输出电压。
4.启动定时器。
通过调用HAL库中的相关函数,启动所选定的定时器开始计数。
定时器计数到达设定的计数周期后,将会产生一个PWM信号。
5.调整PWM信号的占空比。
通过修改PWM输出通道的占空比,可以改变PWM信号的高电平时间。
通过调整占空比的大小,可以控制PWM信号的输出电压。
6.实时调整PWM信号的频率和占空比。
通过修改定时器的预分频因子和计数周期,可以调整PWM信号的频率。
通过修改PWM输出通道的占空比,可以调整PWM信号的占空比。
可以根据特定的应用需求,实时调整这些参数,来实现连续可调的PWM信号输出。
下面是一个示例代码,演示如何利用HAL库配置和控制STM32的PWM输出:```c#include "stm32f4xx_hal.h"TIM_HandleTypeDef htim1;void SystemClock_Config(void);static void MX_GPIO_Init(void);static void MX_TIM1_Init(void);int main(void)HAL_Init(;SystemClock_Config(;MX_GPIO_Init(;MX_TIM1_Init(;HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);while (1)uint16_t dutyCycle = 500; // 设置占空比为50%__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, dutyCycle); HAL_Delay(1000); // 延时1sdutyCycle = 1000; // 设置占空比为100%__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, dutyCycle); HAL_Delay(1000); // 延时1s}void SystemClock_Config(void)RCC_OscInitTypeDef RCC_OscInitStruct;RCC_ClkInitTypeDef RCC_ClkInitStruct;__HAL_RCC_PWR_CLK_ENABLE(;__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1 );RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = 25;RCC_OscInitStruct.PLL.PLLN = 336;RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;RCC_OscInitStruct.PLL.PLLQ = 7;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)Error_Handler(;}RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK ,RCC_CLOCKTYPE_PCLK1RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct,FLASH_LATENCY_5) != HAL_OK)Error_Handler(;}void MX_GPIO_Init(void)GPIO_InitTypeDef GPIO_InitStruct;__HAL_RCC_GPIOA_CLK_ENABLE(;GPIO_InitStruct.Pin = GPIO_PIN_8;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);void MX_TIM1_Init(void)TIM_MasterConfigTypeDef sMasterConfig;TIM_OC_InitTypeDef sConfigOC;htim1.Instance = TIM1;htim1.Init.Prescaler = 0;htim1.Init.CounterMode = TIM_COUNTERMODE_UP;htim1.Init.Period = 1000; // 设置计数周期为1000htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)Error_Handler(;}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim1,&sMasterConfig) != HAL_OK)Error_Handler(;}sConfigOC.OCMode = TIM_OCMODE_PWM1;sConfigOC.Pulse = 0; // 初始化占空比为0sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC,TIM_CHANNEL_1) != HAL_OK)Error_Handler(;}```这是一个基本的示例,演示了如何使用HAL库配置和控制STM32的PWM输出。
PWM控制输出代码

PWM控制输出代码#ifndef INCLUDE_H#define INCLUDE_H#include"AT89X51.h"#include"intrins.h"#define uchar unsigned char#define uint unsigned int#define _BV(x) (1<<(x))#define GET_BIT(x,y) (((x)&(1<<(y)))==0?0:1) /*取x变量y位的数据*/ #define SET_BIT(x,y) ((x)|=(0x0001<<(y))) /*置位x变量y位*/#define CLR_BIT(x,y) ((x)&=~(0x0001<<(y))) /*清零x变量y位*/#define LET_BIT(x,y,z) ((x)=(x)&(~(0x0001<<(y)))|(z)<<(y)) /*置位或清零x变量y位*/#define F_CPU 12000000UL /*cpu震荡周期*/#define sei() (EA=1) /*开总中断*/#define cli() (EA=0) /*关总中断*/#endif-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#define KEY_GLOBAL 1#include"Key.h"static uchar keyValueBuff; /*读取键值的缓冲区*/static uchar keyValueOld; /*前一次的键值*/static uchar keyValueTemp; /*键值中间交换变量*/static uint stillTimes; /*键按下保持次数*/static uint stillTimesMax;static uchar get_data_1_count(uchar number);static void read_all_key(uchar *buff);/********************************************函数名称:key_init(void)*函数功能:初始化按键扫描*函数入口:无*函数出口:无*******************************************/void key_init(void){keyValueBuff = 0x00;keyValueOld = 0x00;keyValueTemp = 0x00;stillTimes = 0;stillTimesMax = FIRST_TIMES;}/****************************************************** *函数名称:read_all_key(uchar *buff)*函数功能:扫描按键下的键,将按下的键的位置存入变量buff *函数入口:buff*函数出口:无*******************************************************/ void read_all_key(uchar *buff){if(IN_PRESS_UP==KEY_FORCE_VALUE) //检测按下的键READ_KEY(1,KEY_UP,*buff);elseREAD_KEY(0,KEY_UP,*buff);if(IN_PRESS_DOWN==KEY_FORCE_VALUE)READ_KEY(1,KEY_DOWN,*buff);elseREAD_KEY(0,KEY_DOWN,*buff);}/****************************************************** *函数名称:get_key_value(void)*函数功能:读取键值*函数入口:无*函数出口:返回按下的有效键值*******************************************************/ uchar get_key_value(void){keyValueBuff = 0x00;read_all_key(&keyValueBuff);keyValueTemp = keyValueBuff;delay_us(KEY_DELAY_TIME);read_all_key(&keyValueBuff);#if REPEAT_MODEif(FIRST_TIMES == stillTimesMax){stillTimesMax = OTHER_TIMES;}#endifreturn keyValueTemp;}#elsestillTimes = 0;return 0;#endif}}else{stillTimes = 0;return 0;}return 0;}/********************************************************** *函数名称:get_data_1_count(uchar number)*函数功能:计算uchar类型变量中的数量,用于检测是否多键按下*函数入口:number,需要检测数量的变量*函数出口:返回变量bumber中的数量***********************************************************/ uchar get_data_1_count(uchar number){register uchar i,j = 0;for(i = 0; i < 8; i ++){if( (number&_BV(i)) ){j ++;}}return j;}/********************************************************** *函数名称:delay_us(uint us)*函数功能:毫秒级延时*函数入口:延时计数变量us*函数出口:无***********************************************************/void delay_us(uint us){uchar delayi;while(--us){for(delayi=0;delayi<10;delayi++);}}#include"Include.h"#ifndef KEY_H#define KEY_H 1#ifndef KEY_GLOBAL#define KEY_EXT extern#else#define KEY_EXT#endif#define READ_KEY(x,name,b) ((x)?(b|=name):(b&=~name) )//--------------------------------用户设置区------------------------------------------#define CAN_MORE_PRESS 0 /* 是否允许多键都按: 允许为;不允许为*/#define CAN_REPEAT 1 /* 是否允许重复按键: 允许为;不允许为*/#define REPEAT_MODE 1 /* 重复模式: 先长后短为;相同间隔为*/#define FIRST_TIMES 200 /* 重复按下时,第一次间隔时间*/#define OTHER_TIMES 25 /* 第二次后间隔时间(如果重复模式为时此值无效) */ #define KEY_DELAY_TIME 20 /* 键盘扫描时间间隔XXXus */#define KEY_FORCE_VALUE 0 /*键盘有效电平,为高电平,为低电平*/#define IN_PRESS_UP P1_0 /*1设置键端口*/#define IN_PRESS_DOWN P1_1 /*2设置键端口*//* 键盘重映射注:当前结构下最大按键数为:8; 以进制中的相应位来标识*/enum KEY_VALUE{KEY_UP= 0x01,KEY_DOWN= 0x02,KEY_NULL = 0x00};//------------------------------------------------------------------------------------ KEY_EXT void key_init(void); //键盘扫描初始化KEY_EXT uchar get_key_value(void); //读取有效键值变量KEY_EXT void delay_us(uint us); //us级延时函数#endif#define LED_GLOBAL 1#include"led.h"extern void delay_us(uint us); /*声明微秒级延时函数*/ /*****************************************************函数名称:led_init(void)*函数功能:数码管初始化*函数入口:无*函数出口:无****************************************************/void led_init(void){//数码管显示pwm初始化值,/100ledWrite('1',0x01,DIGITAL);ledWrite('0',0x02,DIGITAL);ledWrite('0',0x03,DIGITAL);}/*********************************************************** *函数名称:ledWrite(uchar c,uchar n,uchar mod)*函数功能:向第n个数码管写mod模式的内容c*函数入口:c为要显示的内容,显示数字时,调用入口应输入数字字符; n为要显示的数码管编号;mod为要显示的模式*函数出口:无*************************************************************/ void ledWrite(uchar c,uchar n,uchar mod){if(CHARACTER==mod) //为任意字段显示LED=c;else if(DIGITAL==mod)LED=segLedCode[c-'0'];switch(n){case 0x01:{LED_CS1=CS_FORCE_VALUE;delay_us(10);LED_CS1=0; //~CS_FORCE_VALUEbreak;}case 0x02:{LED_CS2=CS_FORCE_VALUE;delay_us(10);LED_CS2=0;break;}case 0x03:{LED_CS3=CS_FORCE_VALUE;delay_us(10);LED_CS3=0;break;}default:break;}}/********************************************************* *驱动名称:七段LED数码管驱动*功能:适用于带个锁存器LS373的段数码管显示*修改:修改驱动使其适用于三个数码管显示*版本:V0.0.1*作者:kxm*时间:.06.11*********************************************************/ #ifndef LED_H#define LED_H 1#include"Include.h"#ifndef LED_GLOBAL#define LED_EXT extern#else#define LED_EXT#endif#define CS_FORCE_VALUE 1 /*74LS373片选有效电平*///***************数码管端口定义**************************** #define LED P0 /*定义LED数据端口*/#define LED_CS1 P2_0 /*74LS373锁存器片选端口*/ #define LED_CS2 P2_1 /*74LS373锁存器片选端口*/ #define LED_CS3 P2_2 /*74LS373锁存器片选端口*/ //*********************************************************enum SEG_DISPLAY_MOD{DIGITAL=0x00,CHARACTER=0x01}; /*数码管输出模式,数字或任意字段显示*/ /*高电平驱动*/#ifdef LED_GLOBALuchar segLedCode[10]={0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,0x7f,0x73};/*数码管数码译码数组,led6~led0==a~g,code1~10==0~9*/#endifLED_EXT void led_init(void); /*数码管初始化*/LED_EXT void ledWrite(uchar c,uchar n,uchar mod); /*向第n个数码管写mod模式的内容c*/#endif#define PWM_GLOBAL 1#include"pwm.h"/******************************************************函数名称:pwm_init(void)*函数功能:PWM初始化,设置定时器*函数入口:无*函数出口:无*****************************************************/void pwm_init(void) // 12M{TMOD=0x20; // 定时器模式TL1 = 255-10; // 1msTH1 = 255-10;ET1 = 1; //定时器边沿触发TR1 = 1; //开定时器中断pwmPeriodCont =0x00;pwmH=0x01;}/******************************************************函数名称:void pwm_set(const uchar NewPwmValue)*函数功能:PWM占空比设置*函数入口:无*函数出口:无*****************************************************/void pwm_set(uchar NewPwmValue){if ((NewPwmValue >= 1)&&(NewPwmValue <= 99)) //一个周期里{pwmH = NewPwmValue;}else//若占空比不在...99范围内则输出一个尖脉冲{pwmH =0x01;}}/******************************************************函数名称:pwmProduce(void)*函数功能:定时器溢出中断设置*函数入口:无*函数出口:无*****************************************************/void pwmProduce(void) interrupt 3{pwmPeriodCont++; //PWM定时周期计数加if(pwmPeriodCont<=pwmH)PWM_OUT =1; // 高电平从到...PWM_Helse// 剩下的为低电平时间{PWM_OUT =0;if (pwmPeriodCont >= PWM_Period)// 一个频率周期结束{pwmPeriodCont=0;}}}/************************************************驱动功能:产生pwm,12MHZ晶振下,总周期为*1ms*版本:.0.1*作者:lhw*时间:.06.11***********************************************/#ifndef PWM_H#define PWM_H#include"Include.h"#ifndef PWM_GLOBAL#define PWM_EXT extern#else#define PWM_EXT#endif#define PWM_Period 100 //100%占空比时标数//*******************端口定义**********************sbit PWM_OUT=P1^2; /*pwm输出端口映射*///*************************************************PWM_EXT uchar pwmPeriodCont; // PWM 占空比计数器PWM_EXT uchar pwmH;PWM_EXT void pwm_init(void); /*PWM初始化,设置定时器*/ PWM_EXT void pwm_set(const uchar NewPwmValue); /*PWM占空比设置*/#endif#include"led.h"#include"key.h"#include"pwm.h"static uchar pwmScale; //pwm占空比,1~99 void main(){uchar keyValue;pwm_init(); //初始化pwm,pwm高电平默认值为 key_init();led_init();pwmScale=0x01; //初始化占空比变量,初始值为 sei();while(1){keyValue=get_key_value();if(keyValue!=KEY_NULL){if(keyValue==KEY_UP){if(pwmScale<99)pwmScale++;}if(keyValue==KEY_DOWN){if(pwmScale>1)pwmScale--;}pwm_set(pwmScale);ledWrite(pwmScale%10+'0',0x01,DIGITAL); //显示占空比个位 ledWrite(pwmScale/10+'0',0x02,DIGITAL); //显示占空比十位}}}。
单片机常用c代码

单片机常用c代码在单片机领域,C语言是最常用的编程语言之一。
它具有简单易学、灵活高效的特点,被广泛应用于单片机系统的开发中。
本文将介绍一些常用的单片机C代码,为读者提供参考和学习的资源。
一、IO口控制单片机的IO口是与外部设备连接的重要接口,通过控制IO口的高低电平来实现与外部设备的通信。
以下是常见的IO口控制代码示例:1. 设置IO口为输出模式:```c#define LED_PIN 0 // 指定IO口引脚号void setup() {pinMode(LED_PIN, OUTPUT); // 设置IO口为输出模式}void loop() {digitalWrite(LED_PIN, HIGH); // 设置IO口为高电平delay(1000); // 延迟1秒digitalWrite(LED_PIN, LOW); // 设置IO口为低电平delay(1000); // 延迟1秒```2. 设置IO口为输入模式:```c#define BUTTON_PIN 1 // 指定IO口引脚号void setup() {pinMode(BUTTON_PIN, INPUT); // 设置IO口为输入模式}void loop() {if (digitalRead(BUTTON_PIN) == HIGH) { // 判断IO口电平是否为高电平// 执行相应操作}}```二、定时器控制定时器是单片机中的重要组件,可用于实现精确的时间控制和周期性任务。
以下是常见的定时器控制代码示例:1. 设置定时器计数器和预分频值:void setup() {TCCR1B = (1 << CS12) | (1 << CS10); // 设置定时器1的预分频为1024}void loop() {// 执行相应操作}```2. 设置定时器中断服务程序:```cISR(TIMER1_COMPA_vect) {// 定时器1比较匹配中断服务程序}void setup() {TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10); // 设置定时器1的CTC模式和预分频为1024OCR1A = 15624; // 设置定时器1的比较匹配值,实现1秒中断一次TIMSK1 = (1 << OCIE1A); // 允许定时器1比较匹配中断}void loop() {// 执行相应操作}```三、串口通信串口通信是单片机与计算机或其他外部设备进行数据交互的常用方式。
STCMCU的软件和硬件PCAPWM输出

STCMCU的软件和硬件PCAPWM输出软件⽅式输出PWMPWM⽤于输出强度的控制, 例如灯的亮度, 轮⼦速度等, STC89/90系列没有硬件PWM, 需要使⽤代码模拟使⽤纯循环的⽅式实现PWM⾮中断的实现(SDCC环境编译)#include <8052.h>#define Led10 P0_7typedef unsigned int u16;int atime = 64;// 仅作为延时, pms取值区间为 0 - 64void delay(u16 pms) {u16 x, y;for (x=pms; x>0; x--) {for (y=11; y>0; y--);}}// 这⾥控制占空⽐, i取值区间为 0 - 64,// i越⼤脉冲宽度越低, 因为输出是低位点亮, 所以i越⼤LED越亮void ledfade(u16 i) {Led10 = 0;delay(i);Led10 = 1;delay(atime-i);}int main(void) {u16 a, b;// 每个循环, ⼩灯while(1) {// a增⼤, 脉冲宽度降, 亮度增for (a=0; a<atime; a++) {for (b=0; b < (atime - a)/4; b++) {ledfade(a);}}// a减⼩, 脉冲宽度增, 亮度降for (a=atime; a>0; a--) {for (b=0; b < (atime - a)/4; b++) {ledfade(a);}}}}使⽤中断的⽅式因为需要PWM输出的场景, ⼀般都不会仅仅有PWM输出, 所以通常会做到定时器中断中, 由中断来实现将1和0的时间宽度设置为定时器, 直接做到定时器中断⾥⾯这个代码中1. pwm_flag代表了输出的0和1, 每次定时器中断时进⾏切换, 并设置下⼀次中断的时间宽度2. 缺点: ⽤TR0做开关, 但是这种停⽌⽅式, 停⽌后输出可能还是1/* Global variables and definition */#define PWMPIN P1_0unsigned char pwm_width;bit pwm_flag = 0;void pwm_setup(){TMOD = 0; // Timer mode 0, 13bitpwm_width = 160;EA = 1;ET0 = 1;TR0 = 1;}/* Timer 0 Interrupt service routine */void timer0() interrupt 1{if (!pwm_flag) { /* Start of High level */pwm_flag = 1; /* Set flag */PWMPIN = 1; /* Set PWM o/p pin */TH0 = pwm_width; /* Load timer */TF0 = 0; /* Clear interrupt flag */} else { /* Start of Low level */pwm_flag = 0; /* Clear flag */PWMPIN = 0; /* Clear PWM o/p pin */TH0 = 255 - pwm_width; /* Load timer */TF0 = 0; /* Clear Interrupt flag */}}void pwm_stop(){TR0 = 0; /* Disable timer to disable PWM */}使⽤定时器模式2和中断实现的PWM输出使⽤定时器⼯作模式2定时器通过对变量tt做计数, 与scale做⽐较, 确定是否翻转电压这⾥scale分10个等级, scale=1时占⽐1/10个PWM周期(250us * 10 = 2.5ms), 在主循环⾥改变scale因为是低电平点亮LED, 所以tt<=scale的时间LED是暗的, scale增⼤时亮度变⼩, 这个可以根据⾃⼰电路的情况调整这样存在的问题是修改scale的值时, 可能正好在tt计数范围的中间, 导致输出出现⽑刺, 可以通过增加⼀个中间变量来解决, 在tt计数时⽐较的是这个中间变量, 在周期结束时再⽤新值更新这个中间变量#include<reg51.h>sbit P10 = P1^0;sbit P11 = P1^1;unsigned int scale; //占空⽐控制变量void main(void) {unsigned int n; //延时循环变量TMOD = 0x02; //定时器0,⼯作模式2, 8位定时, TL0溢出时⾃动重载TH0中的值TH0 = 0x06; //定时, 250us⼀个中断 (12M晶振, 12分频后1MHz, 单次1us)TL0 = 0x06; //初始值TR0 = 1; //启动定时器0ET0 = 1; //启动定时器0中断EA = 1; //开启总中断while(1) {for(n = 0; n < 50000; n++); //延时50msscale++; //占空⽐控制, ⾃增if(scale == 10) scale = 0; //使占空⽐从0-10循环变化}}timer0() interrupt 1 {static unsigned int tt; //tt⽤来保存当前时间在⼀个时钟周期的位置tt++; //每中断⼀次,即每经过250us,tt的值⾃加1if (tt == 10) { //中断10次定时2.5mstt = 0; //使tt=0,开始新的周期,达到循环的效果P10 = 0; //点亮LED}if (tt <= scale) { //如果占空⽐与中断次数相同时,此时输出⾼电平P10 = 1; //熄灭LED灯}}使⽤定时器模式2和中断实现的多路PWM输出实现多路PWM输出的思路1. 使⽤⼀个基础定时器, 定时器时间不能太⼤, 例如设置为100us, 可以⽤定时器模式2, 这样初始值能⾃动重置2. 设定⼀个PWM周期, 这个周期就是定时器间隔的整数倍, 例如10倍定时器周期, 就是1000us = 1ms3. 对于每个PWM通道设置⼀个计数, 计数在达到PWM周期时置零, 这是实现PWM周期的基础设置⼀个初始输出, ⾼电平或低电平设置⼀个输出宽度, 计数达到这个宽度值时翻转. 这个宽度决定了输出翻转的时间, ⽤于控制占空⽐4. 因为每个指令的执⾏时间需要1-2个CPU周期, 所以当通道数增加后, 误差会增⼤代码例⼦: 这⾥⽤8个位指定4个轮⼦的PWM输出, 每个轮⼦两位是为了控制轮⼦的正反向#include <reg52.h>typedef unsigned int u16;typedef unsigned char u8;// Wheel 0sbit P1_0 = P1^0;sbit P1_1 = P1^1;// Wheel 1sbit P1_2 = P1^2;sbit P1_3 = P1^3;// Wheel 2sbit P1_4 = P1^4;sbit P1_5 = P1^5;// Wheel 3sbit P1_6 = P1^6;sbit P1_7 = P1^7;/*Duty Cycle = Toogle_P1_x / PWM_Period;*/u8 PWM_Period = 128; // PWM Period = N * Timer delay(100us), between 10 - 254 u8 Toggle_W0 = 0; // Toggle of Wheel 0u8 Dir_W0 = 0; // Direction, 0:P1_0=0,P1_1=PWM, 1:P1_1=0,P1_0=PWMu8 Toggle_W1 = 0; // Toggle of Wheel 1u8 Dir_W1 = 0; // Direction, 0:P1_2=0,P1_3=PWM, 1:P1_3=0,P1_2=PWMu8 Count_W0, Count_W1;void Time0_Init(void){TMOD = 0x02; // Mode 2, 8-bit and auto-reloadTH0 = 0x9C; // 0x9c = 156, timer of 100us (12MHz OSC)TL0 = 0x9C;ET0 = 1;EA = 1;TR0 = 1;EX0 = 1; EX1 = 1; // Enable external interrupt 0 and 1IT0 = 1; IT1 = 1; // Toggle = jump}void main(){Time0_Init();while(1);}void Timer0_IT() interrupt 1{// W0if(Count_W0 == Toggle_W0) {if (Dir_W0 == 0) { // P1_1=PWMP1_1 = 0;} else { // P1_0=PWMP1_0 = 0;}}if(Count_W0 == PWM_Period - 1) {Count_W0 = 0;if (Dir_W0 == 0) {P1_0 = 0;P1_1 = 1;} else {P1_0 = 1;P1_1 = 0;}} else {Count_W0++;}// W1if(Count_W1 == Toggle_W1) {if (Dir_W1 == 0) { // P1_3=PWMP1_3 = 0;} else { // P1_2=PWMP1_2 = 0;}}if(Count_W1 == PWM_Period - 1) {Count_W1 = 0;if (Dir_W1 == 0) {P1_2 = 0;P1_3 = 1;} else {P1_2 = 1;P1_3 = 0;}} else {Count_W1++;}}// W0 dir0->maxvoid W0_dir0(void){if (Dir_W0 == 0) {Toggle_W0++;if(Toggle_W0 > PWM_Period) { Toggle_W0 = PWM_Period; }} else {Toggle_W0--;if(Toggle_W0 == 0) {Dir_W0 = 0;}}}// W0 dir1->maxvoid W0_dir1(void){if (Dir_W0 == 0) {Toggle_W0--;if(Toggle_W0 == 0) {Dir_W0 = 1;}} else {Toggle_W0++;if(Toggle_W0 > PWM_Period) { Toggle_W0 = PWM_Period; }}}// W1 dir0->maxvoid W1_dir0(void){if (Dir_W1 == 0) {Toggle_W1++;if(Toggle_W1 > PWM_Period) { Toggle_W1 = PWM_Period; }} else {Toggle_W1--;if(Toggle_W1 == 0) {Dir_W1 = 0;}}}// W1 dir1->maxvoid W1_dir1(void){if (Dir_W1 == 0) {Toggle_W1--;if(Toggle_W1 == 0) {Dir_W1 = 1;}} else {Toggle_W1++;if(Toggle_W1 > PWM_Period) { Toggle_W1 = PWM_Period; }}}void IT0_INT() interrupt 0{W1_dir0();}void IT1_INT() interrupt 2{W1_dir1();}硬件PWM51系列单⽚机的增强型版本, 有些带PCA(Programmable Counter Array 可编程计数序列)模块, 可以通过PCA实现PWM的输出.PCA介绍PCA其实就是⼀个增强型的计数器, 这个计数器中的⼀些元素是可以在代码中设置的, 例如可以设置的计数脉冲源, 可以来⾃于系统时钟, 系统时钟可以是不分频, 2分频, 4分频, 6分频, 8分频等; 来⾃计数器; 来⾃外部输⼊的时钟可以设置计数的触发条件, 上升沿还是下降沿, 或者都计数. 最后这个计数⽅式, 可以⽤来计算脉宽可以设置16位的⽐较值不占⽤CPU资源, 这点很重要, 可以使输出更加精确和稳定因为上⼀点, 有些型号可以做到在CPU处于IDLE状态时继续计数(输出)可以⽤PCA实现PWM输出功能STC12C5A60S2系列PCA实现的PWM参考STC12C5A60S2的⼿册有两路输出, 默认PWM0:P1.3, PWM1:P1.4, 可以换到P4⼝: PWM0:P4.2, PWM1:P4.3这个在AUXR1⾥⾯控制两路共⽤PCA定时器, 定时器的频率由CMOD控制因为PWM输出是8位的, 所以定时器的频率/256就是PWM频率两路输出的占空⽐是独⽴变化的, 与当前的[EPCnL, CCAPnL]的值有关前者的值在 PCA_PWM0 PCA_PWM1 ⾥控制后者的值在 CCAP0L,CCAP0H 和 CCAP1L,CCAP1H ⾥控制先输出低, 当CL的值⼤于等于[EPCnL, CCAPnL]时, 输出为⾼当CL由FF变为00时, 输出变低, 同时⾃动将[EPCnH, CCAPnH]的值装载到[EPCnL, CCAPnL], 实现⽆⼲扰更新PWM占空⽐下⾯的代码中, CCAP1H 控制的就是装载值, CCAP1L 控制的是⽐较值, PCA_PWM1 控制的是EPCnH 和 EPCnL如果 EPCnL = 0, 那么正常输出如果 EPCnL = 1, 那么会⼀直输出低电平#include <STC12C5A60S2.H>void main() {CCON = 0; // Initial PCA control register// PCA timer stop running// Clear CF flag// Clear all module interrupt flagCL = 0; // Reset PCA base timerCH = 0;CMOD = 0x02; // Set PCA timer clock source as Fosc/2// Disable PCA timer overflow interruptCCAP0H = CCAP0L = 0x80; // PWM0 port output 50% duty cycle suquare waveCCAPM0 = 0x42; // PCA module-0 as 8-bit PWM, no PAC interruptCCAP1H = CCAP1L = 0xFF; // PWM1port output 0% duty cycle square wavePCA_PWM1 = 0x03; // PWM will keep low levelCCAPM1 = 0x42; // PCA module-0 as 8-bit PWM, no PAC interruptCR = 1; // PCA timer start runwhile(1);}对PCA_PWM1的说明;PCA_PWMn: 7 6 5 4 3 2 1 0; EBSn_1 EBSn_0 - - - - EPCnH EPCnL;B5-B2: 保留;B1(EPCnH): 在PWM模式下,与CCAPnH组成9位数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#ifndef INCLUDE_H#define INCLUDE_H#include"AT89X51.h"#include"intrins.h"#define uchar unsigned char#define uint unsigned int#define _BV(x) (1<<(x))#define GET_BIT(x,y) (((x)&(1<<(y)))==0?0:1) /*取x变量y位的数据*/#define SET_BIT(x,y) ((x)|=(0x0001<<(y))) /*置位x变量y位*/#define CLR_BIT(x,y) ((x)&=~(0x0001<<(y))) /*清零x变量y位*/#define LET_BIT(x,y,z) ((x)=(x)&(~(0x0001<<(y)))|(z)<<(y)) /*置位或清零x变量y位*/#define F_CPU 12000000UL /*cpu震荡周期*/#define sei() (EA=1) /*开总中断*/#define cli() (EA=0) /*关总中断*/#endif-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#define KEY_GLOBAL 1#include"Key.h"static uchar keyValueBuff; /*读取键值的缓冲区*/static uchar keyValueOld; /*前一次的键值*/static uchar keyValueTemp; /*键值中间交换变量*/static uint stillTimes; /*键按下保持次数*/static uint stillTimesMax;static uchar get_data_1_count(uchar number);static void read_all_key(uchar *buff);/********************************************函数名称:key_init(void)*函数功能:初始化按键扫描*函数入口:无*函数出口:无*******************************************/void key_init(void){keyValueBuff = 0x00;keyValueOld = 0x00;keyValueTemp = 0x00;stillTimes = 0;stillTimesMax = FIRST_TIMES;}/****************************************************** *函数名称:read_all_key(uchar *buff)*函数功能:扫描按键下的键,将按下的键的位置存入变量buff *函数入口:buff*函数出口:无*******************************************************/ void read_all_key(uchar *buff){if(IN_PRESS_UP==KEY_FORCE_VALUE) //检测按下的键READ_KEY(1,KEY_UP,*buff);elseREAD_KEY(0,KEY_UP,*buff);if(IN_PRESS_DOWN==KEY_FORCE_VALUE)READ_KEY(1,KEY_DOWN,*buff);elseREAD_KEY(0,KEY_DOWN,*buff);}/****************************************************** *函数名称:get_key_value(void)*函数功能:读取键值*函数入口:无*函数出口:返回按下的有效键值*******************************************************/ uchar get_key_value(void){keyValueBuff = 0x00;read_all_key(&keyValueBuff);keyValueTemp = keyValueBuff;delay_us(KEY_DELAY_TIME);read_all_key(&keyValueBuff);/* 两次读到的键盘值相同则为有效键盘值*/if( keyValueTemp == keyValueBuff ){if(keyValueTemp == 0){keyValueOld = 0;stillTimes = 0;stillTimesMax = FIRST_TIMES;return 0;}else if(keyValueOld != keyValueTemp){stillTimes = 0;keyValueOld = keyValueTemp;#if CAN_MORE_PRESSreturn keyValueTemp;#elseif( 1 == get_data_1_count(keyValueTemp) ) {return keyValueTemp;}else{return 0;}#endif}else if(keyValueOld == keyValueTemp){#if CAN_MORE_PRESS == 0if( 1 != get_data_1_count(keyValueTemp) ) {stillTimes = 0;return 0;}#endif#if CAN_REPEATstillTimes ++;if(stillTimes > stillTimesMax){stillTimes = 0;#if REPEAT_MODEif(FIRST_TIMES == stillTimesMax){stillTimesMax = OTHER_TIMES;}#endifreturn keyValueTemp;}#elsestillTimes = 0;return 0;#endif}}else{stillTimes = 0;return 0;}return 0;}/********************************************************** *函数名称:get_data_1_count(uchar number)*函数功能:计算uchar类型变量中的数量,用于检测是否多键按下*函数入口:number,需要检测数量的变量*函数出口:返回变量bumber中的数量***********************************************************/ uchar get_data_1_count(uchar number){register uchar i,j = 0;for(i = 0; i < 8; i ++){if( (number&_BV(i)) ){j ++;}}return j;}/********************************************************** *函数名称:delay_us(uint us)*函数功能:毫秒级延时*函数入口:延时计数变量us*函数出口:无***********************************************************/void delay_us(uint us){uchar delayi;while(--us){for(delayi=0;delayi<10;delayi++);}}#include"Include.h"#ifndef KEY_H#define KEY_H 1#ifndef KEY_GLOBAL#define KEY_EXT extern#else#define KEY_EXT#endif#define READ_KEY(x,name,b) ((x)?(b|=name):(b&=~name) )//--------------------------------用户设置区------------------------------------------#define CAN_MORE_PRESS 0 /* 是否允许多键都按: 允许为;不允许为*/#define CAN_REPEAT 1 /* 是否允许重复按键: 允许为;不允许为*/#define REPEAT_MODE 1 /* 重复模式: 先长后短为;相同间隔为*/#define FIRST_TIMES 200 /* 重复按下时,第一次间隔时间*/#define OTHER_TIMES 25 /* 第二次后间隔时间(如果重复模式为时此值无效) */ #define KEY_DELAY_TIME 20 /* 键盘扫描时间间隔XXXus */#define KEY_FORCE_VALUE 0 /*键盘有效电平,为高电平,为低电平*/#define IN_PRESS_UP P1_0 /*1设置键端口*/#define IN_PRESS_DOWN P1_1 /*2设置键端口*//* 键盘重映射注:当前结构下最大按键数为:8; 以进制中的相应位来标识*/enum KEY_VALUE{KEY_UP= 0x01,KEY_DOWN= 0x02,KEY_NULL = 0x00};//------------------------------------------------------------------------------------ KEY_EXT void key_init(void); //键盘扫描初始化KEY_EXT uchar get_key_value(void); //读取有效键值变量KEY_EXT void delay_us(uint us); //us级延时函数#endif#define LED_GLOBAL 1#include"led.h"extern void delay_us(uint us); /*声明微秒级延时函数*/ /*****************************************************函数名称:led_init(void)*函数功能:数码管初始化*函数入口:无*函数出口:无****************************************************/void led_init(void){//数码管显示pwm初始化值,/100ledWrite('1',0x01,DIGITAL);ledWrite('0',0x02,DIGITAL);ledWrite('0',0x03,DIGITAL);}/************************************************************函数名称:ledWrite(uchar c,uchar n,uchar mod)*函数功能:向第n个数码管写mod模式的内容c*函数入口:c为要显示的内容,显示数字时,调用入口应输入数字字符;n为要显示的数码管编号;mod为要显示的模式*函数出口:无*************************************************************/void ledWrite(uchar c,uchar n,uchar mod){if(CHARACTER==mod) //为任意字段显示LED=c;else if(DIGITAL==mod)LED=segLedCode[c-'0'];switch(n){case 0x01:{LED_CS1=CS_FORCE_VALUE;delay_us(10);LED_CS1=0; //~CS_FORCE_VALUE break;}case 0x02:{LED_CS2=CS_FORCE_VALUE;delay_us(10);LED_CS2=0;break;}case 0x03:{LED_CS3=CS_FORCE_VALUE;delay_us(10);LED_CS3=0;break;}default:break;}}/**********************************************************驱动名称:七段LED数码管驱动*功能:适用于带个锁存器LS373的段数码管显示*修改:修改驱动使其适用于三个数码管显示*版本:V0.0.1*作者:kxm*时间:.06.11*********************************************************/#ifndef LED_H#define LED_H 1#include"Include.h"#ifndef LED_GLOBAL#define LED_EXT extern#else#define LED_EXT#endif#define CS_FORCE_VALUE 1 /*74LS373片选有效电平*///***************数码管端口定义****************************#define LED P0 /*定义LED数据端口*/#define LED_CS1 P2_0 /*74LS373锁存器片选端口*/#define LED_CS2 P2_1 /*74LS373锁存器片选端口*/#define LED_CS3 P2_2 /*74LS373锁存器片选端口*///*********************************************************enum SEG_DISPLAY_MOD{DIGITAL=0x00,CHARACTER=0x01}; /*数码管输出模式,数字或任意字段显示*/ /*高电平驱动*/#ifdef LED_GLOBALuchar segLedCode[10]={0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,0x7f,0x73};/*数码管数码译码数组,led6~led0==a~g,code1~10==0~9*/#endifLED_EXT void led_init(void); /*数码管初始化*/LED_EXT void ledWrite(uchar c,uchar n,uchar mod); /*向第n个数码管写mod模式的内容c*/#endif#define PWM_GLOBAL 1#include"pwm.h"/******************************************************函数名称:pwm_init(void)*函数功能:PWM初始化,设置定时器*函数入口:无*函数出口:无*****************************************************/void pwm_init(void) // 12M{TMOD=0x20; // 定时器模式TL1 = 255-10; // 1msTH1 = 255-10;ET1 = 1; //定时器边沿触发TR1 = 1; //开定时器中断pwmPeriodCont =0x00;pwmH=0x01;}/******************************************************函数名称:void pwm_set(const uchar NewPwmValue)*函数功能:PWM占空比设置*函数入口:无*函数出口:无*****************************************************/void pwm_set(uchar NewPwmValue){if ((NewPwmValue >= 1)&&(NewPwmValue <= 99)) //一个周期里{pwmH = NewPwmValue;}else//若占空比不在...99范围内则输出一个尖脉冲{pwmH =0x01;}}/******************************************************函数名称:pwmProduce(void)*函数功能:定时器溢出中断设置*函数入口:无*函数出口:无*****************************************************/void pwmProduce(void) interrupt 3{pwmPeriodCont++; //PWM定时周期计数加if(pwmPeriodCont<=pwmH)PWM_OUT =1; // 高电平从到...PWM_Helse// 剩下的为低电平时间{PWM_OUT =0;if (pwmPeriodCont >= PWM_Period)// 一个频率周期结束{pwmPeriodCont=0;}}}/************************************************驱动功能:产生pwm,12MHZ晶振下,总周期为*1ms*版本:.0.1*作者:lhw*时间:.06.11***********************************************/#ifndef PWM_H#define PWM_H#include"Include.h"#ifndef PWM_GLOBAL#define PWM_EXT extern#else#define PWM_EXT#endif#define PWM_Period 100 //100%占空比时标数//*******************端口定义**********************sbit PWM_OUT=P1^2; /*pwm输出端口映射*///*************************************************PWM_EXT uchar pwmPeriodCont; // PWM 占空比计数器PWM_EXT uchar pwmH;PWM_EXT void pwm_init(void); /*PWM初始化,设置定时器*/ PWM_EXT void pwm_set(const uchar NewPwmValue); /*PWM占空比设置*/#endif#include"led.h"#include"key.h"#include"pwm.h"static uchar pwmScale; //pwm占空比,1~99void main(){uchar keyValue;pwm_init(); //初始化pwm,pwm高电平默认值为key_init();led_init();pwmScale=0x01; //初始化占空比变量,初始值为sei();while(1){keyValue=get_key_value();if(keyValue!=KEY_NULL){if(keyValue==KEY_UP){if(pwmScale<99)pwmScale++;}if(keyValue==KEY_DOWN){if(pwmScale>1)pwmScale--;}pwm_set(pwmScale);ledWrite(pwmScale%10+'0',0x01,DIGITAL); //显示占空比个位 ledWrite(pwmScale/10+'0',0x02,DIGITAL); //显示占空比十位}}}。