最近学习用TOUT0、TOUT1做PWM输出。经过研究,可以用TOUT0做PWM输出,TOUT1却不行。我是参阅周立功的一些资料做的。此驱动如果用于TOUT1做PWM输出是否要改动?另外,我在做TOUT1输出时,就是把实验程序中的
BYTE prescale[2] = {0, 97}; BYTE prescale[2] = {1, 97};
BYTE divider[2] = {0, 2}; BYTE divider[2] = {1, 2};
DWORD buff[3] = {0, FREQ_VALUE, m_slider_pos}; 改为: DWORD buff[3] = {1, FREQ_VALUE, m_slider_pos};
DWORD timer = 0, curfreq, actlen; DWORD timer = 1, curfreq, actlen;
这样做是不是就够了?我实验的结果是TOUT1上没有PWM输出信号。驱动和程序是否还要哪里改动?
现贴出驱动程序和实验程序,请大家帮忙看看。
驱动程序:
#include <windows.h>
#include <types.h>
#include <excpt.h>
#include <tchar.h>
#include <cardserv.h>
#include <cardapi.h>
#include <tuple.h>
#include <devload.h>
#include <diskio.h>
#include <nkintr.h>
#include <windev.h>
#include <s3c2440a.h>
#include "pwm.h"
#define PRIVATE static
#define PUBLIC
/* GPIO,PWM 寄存器对应的虚拟地址 */
PRIVATE volatile S3C2440A_IOPORT_REG * v_pIOPregs;
PRIVATE volatile S3C2440A_PWM_REG * v_PWMregs;
PRIVATE DWORD m_s3c2440_pclk;
PRIVATE DWORD g_OpenCount = 0;
#define DEFAULT_S3C2440A_PCLK (203000000 / 4)
/*******************************************************************************************
函数名称: PWM_ConfigPin
描 述: 初始化 GPB0 为 TOUT0 功能
输入参数: DWORD t_num: 定时器编号: 0 或 1
输出参数: 无
返 回: 无
********************************************************************************************/
PRIVATE void PWM_ConfigPin(DWORD t_num)
{
if (t_num == 0)
{
// TOUT0口设置
v_pIOPregs->GPBCON &= ~(0x03 << 0);
v_pIOPregs->GPBCON |= (0x02 << 0); // rGPBCON[1:0] = 10b,设置TOUT0功能
v_pIOPregs->GPBUP |= 0x1 << 0;
}
else if (t_num == 1)
{
// TOUT1口设置
v_pIOPregs->GPBCON &= ~(0x03 << 2);
v_pIOPregs->GPBCON |= (0x02 << 1); // rGPBCON[3:2] = 10b,设置TOUT1功能
v_pIOPregs->GPBUP |= 0x1 << 1;
}
}
/*******************************************************************************************
函数名称: PWM_ConfigPWMDefault
描 述: 恢复 PWM0 和 PWM1 的硬件为默认值
输入参数: DWORD t_num: 定时器编号: 0 或 1
输出参数: 无
返 回: 无
********************************************************************************************/
PRIVATE void PWM_ConfigPWMDefault(DWORD t_num)
{
if (t_num == 0)
{
// TOUT0口设置
v_pIOPregs->GPBCON &= ~(0x03 << 0); // rGPBCON[1:0] = 00b,设置GPB0 为输入GPIO
v_pIOPregs->GPBUP &= ~(0x1 << 0); // 上拉
v_PWMregs->TCFG0 &= ~0xFF; // Timer0 预分频恢复为0
v_PWMregs->TCFG1 &= ~0x0F; // MUX0
v_PWMregs->TCON &= ~0x1F; // Timer0 TCON
v_PWMregs->TCNTB0 = 0; // 定时值(PWM周期)
v_PWMregs->TCMPB0 = 0; // 设置PWM占空比
}
if (t_num == 1)
{
// TOUT1口设置
v_pIOPregs->GPBCON &= ~(0x03 << 2); // rGPBCON[1:0] = 00b,设置GPB1 为输入GPIO
v_pIOPregs->GPBUP &= ~(0x1 << 1); // 上拉
v_PWMregs->TCFG0 &= ~0xFF; // Timer1 预分频恢复为0
v_PWMregs->TCFG1 &= ~(0x0F << 4); // MUX1
v_PWMregs->TCON &= ~(0x0F00 << 8); // Timer1 TCON
v_PWMregs->TCNTB1 = 0; // 定时值(PWM周期)
v_PWMregs->TCMPB1 = 0; // 设置PWM占空比
}
}
/*******************************************************************************************
函数名称: PWM_InitializeAddresses
描 述: 取得相关寄存器的虚拟地址
输入参数: 无
输出参数: 无
返 回: > 0 分配到的虚拟地址; FALSE: 失败
********************************************************************************************/
PRIVATE BOOL PWM_InitializeAddresses(void)
{
BOOL RetValue = TRUE;
// IO Register Allocation
v_pIOPregs = (volatile S3C2440A_IOPORT_REG *)VirtualAlloc(0, sizeof(S3C2440A_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);
if (v_pIOPregs == NULL)
{
ERRORMSG(1,(TEXT("For IOPregs : VirtualAlloc failed!\r\n")));
RetValue = FALSE;
}
else
{
if (!VirtualCopy((PVOID)v_pIOPregs, (PVOID)(S3C2440A_BASE_REG_PA_IOPORT >> 8), sizeof(S3C2440A_IOPORT_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
{
ERRORMSG(1,(TEXT("For IOPregs: VirtualCopy failed!\r\n")));
RetValue = FALSE;
}
}
if (!RetValue)
{
RETAILMSG (1, (TEXT("::: PWM_InitializeAddresses - Fail!!\r\n") ));
if (v_pIOPregs)
VirtualFree((PVOID) v_pIOPregs, 0, MEM_RELEASE);
v_pIOPregs = NULL;
RetValue = FALSE;
return RetValue;
}
//
// PWM Register Allocation
//
v_PWMregs = (volatile S3C2440A_PWM_REG *)VirtualAlloc(0, sizeof(S3C2440A_PWM_REG), MEM_RESERVE, PAGE_NOACCESS);
if (v_PWMregs == NULL)
{
ERRORMSG(1,(TEXT("For PWMregs : VirtualAlloc failed!\r\n")));
RetValue = FALSE;
}
else
{
if (!VirtualCopy((PVOID)v_PWMregs, (PVOID)(S3C2440A_BASE_REG_PA_PWM >> 8), sizeof(S3C2440A_PWM_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
{
ERRORMSG(1,(TEXT("For PWMregs: VirtualCopy failed!\r\n")));
RetValue = FALSE;
}
}
if (!RetValue)
{
RETAILMSG (1, (TEXT("::: PWM_InitializeAddresses - Fail!!\r\n") ));
if (v_PWMregs)
VirtualFree((PVOID) v_PWMregs, 0, MEM_RELEASE);
v_PWMregs = NULL;
}
return(RetValue);
}
/*******************************************************************************************
函数名称: PWM_SetPrescaler
描 述: 设置定时器 0 和 1 的预分频值
输入参数: BYTE t_num: 定时器编号: 0 或 1
BYTE value: 预分频值, 值从 0 ~ 255
输出参数: 无
返 回: 无
********************************************************************************************/
void PWM_SetPrescaler(BYTE t_num, BYTE value)
{
if ((t_num == 0) || (t_num == 1))
{
v_PWMregs->TCFG0 &= ~0xFF;
v_PWMregs->TCFG0 |= value; // 设置定时器 0,1 的预分频值
}
}
/*******************************************************************************************
函数名称: PWM_SetDivider
描 述: 设置定时器 0 和 1 的分频器分频值
输入参数: BYTE t_num: 定时器编号: 0 或 1
BYTE value: 分频值: 2,4,8,16
输出参数: 无
返 回: TRUE: 成功; FALSE: 失败
********************************************************************************************/
BOOL PWM_SetDivider(BYTE t_num, BYTE value)
{
BYTE tmp;
if ((t_num > 1) || (value > 16))
return FALSE;
for (tmp = 0; tmp < 4; tmp++)
{
if ((2 << tmp) == value)
break;
}
if (tmp > 4)
return FALSE; // value 取值只能为 2,4,8,16
if (t_num == 0)
{
v_PWMregs->TCFG1 &= ~0x0F;
v_PWMregs->TCFG1 |= tmp;
}
else
{
v_PWMregs->TCFG1 &= ~(0x0F << 4);
v_PWMregs->TCFG1 |= (tmp << 4);
}
return TRUE;
}
/*******************************************************************************************
函数名称: PWM_StartPWM
描 述: 设置定时器 0 或 1 的周期和占空比, 并启动 pwm
输入参数: DWORD t_num: 定时器编号: 0 或 1
DWORD cycle: 取值为 0 ~ 65535
DWORD duty : 取值为 0 ~ 63535
输出参数: 无
返 回: TRUE: 成功; FALSE: 失败
注 意: 占空比为 duty / cycle
********************************************************************************************/
BOOL PWM_StartPWM(DWORD t_num, DWORD cycle, DWORD duty)
{
DWORD tmp;
if ((cycle > 65535)||(duty > 65535))
return FALSE;
if ((duty > cycle)||(t_num > 1))
return FALSE;
if (t_num == 0)
{
PWM_ConfigPin(0);
v_PWMregs->TCNTB0 = cycle & 0xFFFF; // 定时值(PWM周期)
v_PWMregs->TCMPB0 = duty & 0xFFFF; // 设置PWM占空比
tmp = v_PWMregs->TCON;
if(tmp & (1 << 2))
{
tmp = tmp & (~0x0F) | (1 << 1); // 更新TCNTB0, TCMPB0
v_PWMregs->TCON = tmp;
}
else
{
tmp = tmp & (~0x0F) | (1 << 1) | (1 << 2); // 更新TCNTB0, TCMPB0
v_PWMregs->TCON = tmp; // TOUT0翻转输出
}
tmp = v_PWMregs->TCON;
tmp = tmp & (~0x0F) | (1 << 0) | (1 << 3);
v_PWMregs->TCON = tmp; // 开始定时器0, 自动加载模式
}
else
{
PWM_ConfigPin(1);
v_PWMregs->TCNTB1 = cycle & 0xFFFF; // 定时值(PWM周期)
v_PWMregs->TCMPB1 = duty & 0xFFFF; // 设置PWM占空比
tmp = v_PWMregs->TCON;
if(v_PWMregs->TCON & (1 << 10))
{
tmp = tmp & (~0xF0) | (1 << 9); // 更新TCNTB1, TCMPB1
v_PWMregs->TCON = tmp;
}
else
{
tmp = tmp & (~0xF0) | (1 << 9) | (1 << 10); // TOUT1翻转输出
v_PWMregs->TCON = tmp;
}
tmp = v_PWMregs->TCON;
tmp = tmp & (~0xF0) | (1 << 8) | (1 << 11); // 开始定时器1, 自动加载模式
v_PWMregs->TCON = tmp;
}
return TRUE;
}
/*******************************************************************************************
函数名称: PWM_GetFrequency
描 述: 获取定时器 0 和 1 输出的 PWM 频率
输入参数: DWORD t_num: 定时器编号: 0 或 1
输出参数: DWORD *frequency: PWM 的输出频率
返 回: TRUE: 成功; FALSE: 失败
********************************************************************************************/
const BYTE MUX_Tbl[4] = {2, 4, 8, 16};
BOOL PWM_GetFrequency(DWORD t_num, DWORD *frequency)
{
DWORD freq;
DWORD t_Mux;
if (t_num > 1) return FALSE;
freq = m_s3c2440_pclk / ((v_PWMregs->TCFG0 & 0xFF) + 1); /* 预分频 */
if (t_num == 0)
{
t_Mux = v_PWMregs->TCFG1 & 0x0F; /* [3:0]位 */
if (t_Mux <= 3)
freq = freq / MUX_Tbl[t_Mux];
else
return FALSE;
freq = freq / v_PWMregs->TCNTB0;
}
else
{
t_Mux = (v_PWMregs->TCFG1 & 0xF0) << 4; /* [7:4]位 */
if (t_Mux <= 3)
freq = freq / MUX_Tbl[t_Mux];
else
return FALSE;
freq = freq / v_PWMregs->TCNTB1;
}
*frequency = freq;
return TRUE;
}
/*******************************************************************************************
函数名称: PWM_Init
描 述: 驱动程序初始化函数
输入参数: DWORD dwContext: 设备管理器传递给本驱动的参数, 通常为流接口驱动在注册表内的位置
输出参数: 无
返 回: 驱动程序句柄
*******************************************************************************************/
PUBLIC DWORD PWM_Init(DWORD dwContext)
{
PROCESSOR_INFO procInfo;
DWORD dwBytesReturned;
// 取得相关寄存器的虚拟地址空间
PWM_InitializeAddresses();
/* get the information of the device */
if (!KernelIoControl(IOCTL_PROCESSOR_INFORMATION, NULL, 0, &procInfo, sizeof(PROCESSOR_INFO), &dwBytesReturned))
{
m_s3c2440_pclk = DEFAULT_S3C2440A_PCLK;
RETAILMSG(TRUE, (TEXT("WARNING: DAC_Init:: failed to obtain processor frequency - using default value (%d).\r\n"), m_s3c2440_pclk));
}
else
{
m_s3c2440_pclk = procInfo.dwClockSpeed;
RETAILMSG(TRUE, (TEXT("INFO: DAC_Init:: using processor frequency reported by the OAL (%d).\r\n"), m_s3c2440_pclk));
}
#if 0
RETAILMSG(TRUE, (TEXT("v_pIOPregs->GPBCON is 0x%x).\r\n"), v_pIOPregs->GPBCON));
RETAILMSG(TRUE, (TEXT("v_PWMregs->TCFG0 is 0x%x).\r\n"), v_PWMregs->TCFG0));
RETAILMSG(TRUE, (TEXT("v_PWMregs->TCFG1 is 0x%x).\r\n"), v_PWMregs->TCFG1));
RETAILMSG(TRUE, (TEXT("v_PWMregs->TCMPB0 is 0x%x).\r\n"), v_PWMregs->TCMPB0));
RETAILMSG(TRUE, (TEXT("v_PWMregs->TCNTB0 is 0x%x).\r\n"), v_PWMregs->TCNTB0));
RETAILMSG(TRUE, (TEXT("v_PWMregs->TCON is 0x%x).\r\n"), v_PWMregs->TCON));
#endif
RETAILMSG(1, (TEXT("::: PWM_Init Sucessfully. \r\n")));
return (DWORD)1;
}
/*******************************************************************************************
函数名称: DllEntry
描 述: 驱动程序动态库入口
输入参数:
输出参数:
返 回:
*******************************************************************************************/
PUBLIC BOOL WINAPI
DllEntry(HANDLE hInstDll, DWORD dwReason, LPVOID lpvReserved)
{
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
RETAILMSG(1, (TEXT("PWM: DLL_PROCESS_ATTACH\r\n")));
DisableThreadLibraryCalls((HMODULE) hInstDll);
break;
case DLL_PROCESS_DETACH:
RETAILMSG(1, (TEXT("PWM: DLL_PROCESS_DETACH\r\n")));
break;
}
return (TRUE);
}
/*******************************************************************************************
函数名称: PWM_Close
描 述: 驱动程序关闭函数
输入参数: DWORD Handle: 驱动程序引用事例句柄
输出参数: 无
返 回: FALSE: 失败 TRUE: 成功
*******************************************************************************************/
BOOL PWM_Close(DWORD Handle)
{
if (g_OpenCount > 0)
{
PWM_ConfigPWMDefault(0); /* 恢复 PWM 相关硬件为默认值 */
PWM_ConfigPWMDefault(1);
}
g_OpenCount = 0;
return TRUE;
} // PWM_Close
/*******************************************************************************************
函数名称: PWM_Deinit
描 述: 驱动程序卸载函数
输入参数: DWORD dwContext: 驱动程序句柄
输出参数: 无
返 回: FALSE: 失败 TRUE: 成功
*******************************************************************************************/
BOOL PWM_Deinit(DWORD dwContext)
{
PWM_ConfigPWMDefault(0); /* 恢复 PWM 相关硬件为默认值 */
PWM_ConfigPWMDefault(1);
// 释放申请的虚拟空间
if (v_pIOPregs)
VirtualFree((PVOID) v_pIOPregs, 0, MEM_RELEASE);
if (v_PWMregs)
VirtualFree((PVOID) v_PWMregs, 0, MEM_RELEASE);
g_OpenCount = 0;
return TRUE;
} // PWM_Deinit
/*******************************************************************************************
函数名称: PWM_Open
描 述: 打开驱动程序
输入参数: DWORD dwData : 设备驱动程序句柄
DWORD dwAccess : 访问请求代码,是读和写的组合
DWORD dwShareMode: 共享模式
输出参数:
返 回: 驱动程序引用事例句柄
*******************************************************************************************/
DWORD PWM_Open(DWORD dwData, DWORD dwAccess, DWORD dwShareMode)
{
if (g_OpenCount > 0)
return 0;
PWM_ConfigPWMDefault(0); /* 恢复 PWM 相关硬件为默认值 */
PWM_ConfigPWMDefault(1);
g_OpenCount++;
return g_OpenCount;
} // PWM_Open
/*******************************************************************************************
函数名称: PWM_IOControl
描 述: 驱动程序 I/O 请求
输入参数:
输出参数:
返 回: TRUE: 成功 FALSE: 失败
*******************************************************************************************/
BOOL
PWM_IOControl(
DWORD Handle,
DWORD dwIoControlCode,
PBYTE pInBuf,
DWORD nInBufSize,
PBYTE pOutBuf,
DWORD nOutBufSize,
PDWORD pBytesReturned
)
{
BOOL bErr = FALSE;
switch (dwIoControlCode)
{
case IOCTL_PWM_SET_PRESCALER: /* 设置预分频值 */
if (nInBufSize >= 2) /* 需要2个字节缓冲区 */
{
PWM_SetPrescaler(pInBuf[0], pInBuf[1]);
bErr = TRUE;
}
break;
case IOCTL_PWM_SET_DIVIDER:
if (nInBufSize >= 2) /* 需要2个字节缓冲区 */
bErr = PWM_SetDivider(pInBuf[0], pInBuf[1]);
// 设置分频值 (定时器编号, 分频值)
break;
case IOCTL_PWM_START:
if (nInBufSize >= 3) /* 需要3个字缓冲区 */
{
DWORD t_num = *((DWORD *)pInBuf);
DWORD cycle = *((DWORD *)(pInBuf + 4));
DWORD duty = *((DWORD *)(pInBuf + 8));
#if 0
RETAILMSG(TRUE, (TEXT("t_num is 0x%x).\r\n"), t_num));
RETAILMSG(TRUE, (TEXT("cycle is 0x%x).\r\n"), cycle));
RETAILMSG(TRUE, (TEXT("duty is 0x%x).\r\n"), duty));
#endif
bErr = PWM_StartPWM(t_num, cycle, duty);
}
break;
case IOCTL_PWM_GET_FREQUENCY:
if ((nInBufSize >= 0) && (nOutBufSize > 0))
{
DWORD t_num = *((DWORD *)pInBuf);
bErr = PWM_GetFrequency(t_num, (DWORD *)pOutBuf);
*pBytesReturned = 1;
}
break;
default:
break;
}
return bErr;
} // PWM_IOControl
/*******************************************************************************************
函数名称: PWM_Read
描 述: 从 IIC 从机读取数据
输入参数: DWORD Handle : 驱动程序引用事例句柄
LPVOID pBuffer : 接收缓冲区
DWORD dwNumBytes: 要读的字节数
输出参数: 无
返 回: 实际读到字节数
*******************************************************************************************/
DWORD PWM_Read(DWORD Handle, LPVOID pBuffer, DWORD dwNumBytes)
{
return 0;
}
/*******************************************************************************************
函数名称: PWM_Write
描 述: 向 IIC 从机发送数据
输入参数:
输出参数:
返 回: 成功发送的字节数
*******************************************************************************************/
DWORD PWM_Write(DWORD Handle, LPCVOID pBuffer, DWORD dwNumBytes)
{
return 0;
}
/*******************************************************************************************
函数名称: PWM_Seek
描 述: 对设备的数据指针进行操作,本驱动不支持该函数
输入参数:
输出参数:
返 回:
*******************************************************************************************/
DWORD PWM_Seek(DWORD Handle, long lDistance, DWORD dwMoveMethod)
{
return 0;
}
/*******************************************************************************************
函数名称: PWM_PowerUp
描 述: 电源上电驱动处理函数
输入参数:
输出参数:
返 回: 无
*******************************************************************************************/
void PWM_PowerUp(void)
{
return;
}
/*******************************************************************************************
函数名称: PWM_PowerDown
描 述: 电源下电驱动处理函数
输入参数:
输出参数:
返 回: 无
*******************************************************************************************/
void PWM_PowerDown(void)
{
return;
}
实验程序:
// DCMotorDlg.cpp : implementation file
//
#include "stdafx.h"
#include "DCMotor.h"
#include "DCMotorDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CDCMotorDlg dialog
CDCMotorDlg::CDCMotorDlg(CWnd* pParent /*=NULL*/)
: CDialog(CDCMotorDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CDCMotorDlg)
m_strPWMfreq = _T("");
m_strPWMduty = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CDCMotorDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDCMotorDlg)
DDX_Control(pDX, IDC_SLIDER_PWM, m_Slider);
DDX_Text(pDX, IDC_PWM_FREQ, m_strPWMfreq);
DDX_Text(pDX, IDC_PWM_DUTY, m_strPWMduty);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDCMotorDlg, CDialog)
//{{AFX_MSG_MAP(CDCMotorDlg)
ON_BN_CLICKED(IDC_OPEN_PWM, OnOpenPwm)
ON_BN_CLICKED(IDC_CLOSE_PWM, OnClosePwm)
ON_NOTIFY(NM_CUSTOMDRAW, IDC_SLIDER_PWM, OnCustomdrawSliderPwm)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDCMotorDlg message handlers
/***************************************************
实 验 代 码
****************************************************/
#include "pwm.h" /* 包含 PWM 命令代码头文件 */
#include "gpio.h"
HANDLE hPWMFile = INVALID_HANDLE_VALUE; /* PWM 驱动程序设备句柄 */
HANDLE hGPIOFile = INVALID_HANDLE_VALUE; /* GPIO 驱动程序设备句柄 */
#define FREQ_VALUE 255 /* 定义 PWM 频率值*/
BOOL CDCMotorDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
CenterWindow(GetDesktopWindow()); // center to the hpc screen
// TODO: Add extra initialization here
m_Slider.SetRange(0, FREQ_VALUE - 1, TRUE); /* 滑块控件滑动范围 */
m_Slider.SetPos(0); /* 滑块处于0点 */
m_Slider.EnableWindow(FALSE); /* 滑块禁止操作 */
m_strPWMfreq = "0"; /* 频率与占空比都为0 */
m_strPWMduty = "0%";
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
// "打开驱动" 按键单击事件代码
void CDCMotorDlg::OnOpenPwm()
{
BOOL ret;
BYTE pinnum = 1;
// 打开 PWM 驱动
hPWMFile = CreateFile(TEXT("PWM1:"), GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, 0);
if (hPWMFile == INVALID_HANDLE_VALUE)
{
MessageBox(_T("打开 PWM 驱动失败!"));
return;
}
// 打开 GPIO 驱动
hGPIOFile = CreateFile(TEXT("PIO1:"), GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, 0);
if (hGPIOFile == INVALID_HANDLE_VALUE)
{
OnClosePwm();
MessageBox(_T("打开 GPIO 驱动失败!"));
return;
}
// 设置 GPF0 为输出口
ret = ::DeviceIoControl(hGPIOFile, IOCTL_GPF_SET_PIN_OUT, &pinnum, 1,
NULL, 0, NULL, NULL);
if (ret != TRUE)
{
OnClosePwm();
MessageBox(_T("设置 GPF0 为输出失败!"));
return;
}
// 置 GPF0 为低电平
ret = ::DeviceIoControl(hGPIOFile, IOCTL_GPF_CLR_PIN, &pinnum, 1,
NULL, 0, NULL, NULL);
if (ret != TRUE)
{
OnClosePwm();
MessageBox(_T("设置 GPF9 为输出低电平失败!"));
return;
}
CButton *pOpenButton = (CButton*)GetDlgItem(IDC_OPEN_PWM); /* 取得控件指针 */
CButton *pCloseButton = (CButton*)GetDlgItem(IDC_CLOSE_PWM);
pOpenButton->EnableWindow(FALSE); /* 禁止按键 */
pCloseButton->EnableWindow(TRUE); /* 使能按键 */
m_Slider.EnableWindow(TRUE); /* 滑块使能操作 */
MessageBox(_T("打开 PWM 和 GPIO 驱动成功!"));
}
// "关闭驱动" 按键单击事件代码
void CDCMotorDlg::OnClosePwm()
{
if (hPWMFile != INVALID_HANDLE_VALUE)
{
// 关闭 PWM 驱动
CloseHandle(hPWMFile);
hPWMFile = INVALID_HANDLE_VALUE;
}
if (hGPIOFile != INVALID_HANDLE_VALUE)
{
// 关闭 GPIO驱动
CloseHandle(hGPIOFile);
hGPIOFile = INVALID_HANDLE_VALUE;
}
CButton *pOpenButton = (CButton*)GetDlgItem(IDC_OPEN_PWM); /* 取得控件指针 */
CButton *pCloseButton = (CButton*)GetDlgItem(IDC_CLOSE_PWM);
pOpenButton->EnableWindow(TRUE); /* 使能按键 */
pCloseButton->EnableWindow(FALSE); /* 禁止按键 */
}
// 对话框关闭退出处理函数
void CDCMotorDlg::OnDestroy()
{
CDialog::OnDestroy();
OnClosePwm();
}
// 移动滑块控件事件代码
int m_slider_pos = 0;
void CDCMotorDlg::OnCustomdrawSliderPwm(NMHDR* pNMHDR, LRESULT* pResult)
{
BOOL ret;
BYTE prescale[2] = {0, 97};
BYTE divider[2] = {0, 2};
UpdateData(TRUE);
if (((m_Slider.GetPos() - m_slider_pos) == 0) ||
(hPWMFile == INVALID_HANDLE_VALUE) ||
(hGPIOFile == INVALID_HANDLE_VALUE))
return; /* 滑块或驱动未打开, 不驱动电机 */
m_slider_pos = m_Slider.GetPos(); /* 获取滑块当前位置 */
// 设置PWM0定时器预分频值
ret = ::DeviceIoControl(hPWMFile, IOCTL_PWM_SET_PRESCALER, prescale, 2,
NULL, 0, NULL, NULL);
if (ret != TRUE)
{
MessageBox(_T("设置 PWM0 定时器预分频值失败!"));
return;
}
// 设置PWM0定时器分频值
ret = ::DeviceIoControl(hPWMFile, IOCTL_PWM_SET_DIVIDER, divider, 2,
NULL, 0, NULL, NULL);
if (ret != TRUE)
{
MessageBox(_T("设置 PWM0 定时器分频值失败!"));
return;
}
// 启动 PWM0 输出信号
DWORD buff[3] = {0, FREQ_VALUE, m_slider_pos};
ret = ::DeviceIoControl(hPWMFile, IOCTL_PWM_START, buff, 3,
NULL, 0, NULL, NULL);
if (ret != TRUE)
{
MessageBox(_T("启动 PWM0 信号输出失败!"));
return;
}
// 获取 PWM0 输出频率
DWORD timer = 0, curfreq, actlen;
ret = ::DeviceIoControl(hPWMFile, IOCTL_PWM_GET_FREQUENCY, &timer, 1,
&curfreq, 1, &actlen, NULL);
if (ret != TRUE)
{
MessageBox(_T("获取 PWM0 信号输出频率失败!"));
return;
}
m_strPWMfreq.Format(_T("%d"), curfreq); /* 显示 PWM0 频率 */
float duty = (float)m_slider_pos / ((float)FREQ_VALUE) * 100;
m_strPWMduty.Format(_T("%f"), duty);
m_strPWMduty += "%"; /* 显示 PWM0 点空比 */
UpdateData(FALSE); /* 更新显示 */
*pResult = 0;
}