主题 : 用TOUT0、TOUT1做PWM输出 问题 复制链接 | 浏览器收藏 | 打印
级别: 新手上路
UID: 20668
精华: 0
发帖: 19
金钱: 95 两
威望: 19 点
贡献值: 0 点
综合积分: 38 分
注册时间: 2010-05-05
最后登录: 2011-07-25
楼主  发表于: 2011-03-18 18:29

 用TOUT0、TOUT1做PWM输出 问题

最近学习用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;
}


级别: 新手上路
UID: 91495
精华: 0
发帖: 3
金钱: 15 两
威望: 3 点
贡献值: 0 点
综合积分: 6 分
注册时间: 2013-05-10
最后登录: 2013-06-08
1楼  发表于: 2013-06-08 15:55

 回 楼主(gold0076) 的帖子

师兄你好,我也是碰到 了你描述的问题。你现在把问题解决了吗? 我是在mini2440板子送的光盘上的程序改的,我将TOU0改为了TOUT1,通过tcon寄存器控制使能。