硬件平臺:STM32F10X PWM模塊 + JLink + 示波器
軟件平臺:Keil 4
一、基礎知識
首先,根據芯片的型號,STM32小容量、中容量產品和STM32F105xx/STM32F107xx的互聯型產品,包含一個高級控制定時器(TIM1)。大容量產品的STM32F103xx包含有二個高級控制定時器(TIM1和TIM8)。
一個高級定時器可以輸出七路PWM波,而一個通用定時器則最多只能輸出四路互補PWM波。
通用定時器和高級定時器相互獨立,互不影響,可同時操作。
如果需要的PWM 較多,比如控制六軸的話,可以自行選取不同的定時器,一個不夠的話可選兩個。
其次,每個通用的定時器一般只有4路通道,每個通道有一個比較寄存器,初始化的時候設置不同的值后,可以生成4路PWM信號,不過這4路的PWM頻率相同,占空比可以不一樣。
最后,有任何關于引腳復用、及相關寄存器的具體問題,以相應的數據手冊為準。
PWM的實質還是定時器TIMER模塊的使用。
二、相應模塊
程序涉及的模塊有:
RCC:復位及時鐘控制模塊,用于初始化STM32 USART外設時鐘及IO口復用時鐘;
GPIO:通用輸入輸出口復用配置模塊;
Delay:利用系統時鐘SysTick,也號稱“滴答”,寫的延時模塊;
Led:系統運行提示模塊;
Timer:定時器模塊配置,PWM配置也在其中。
三:代碼
RCC
#include "Rcc.h"
void RCC_Init(void)
{
ErrorStatus HSEStartUpStatus;
//定義枚舉類型錯誤狀態變量
RCC_DeInit();//復位系統時鐘設置
RCC_HSEConfig(RCC_HSE_ON);
//打開外部高速時鐘晶振,使能HSE
/*RCC_HSE_ON 開
_off 關 _bypass hse晶振被外部時鐘旁路*/
HSEStartUpStatus = RCC_WaitForHSEStartUp();
/*RCC_WaitForHSEStartUp()返回一個ErrorStatus枚舉值,
success好,error未好*/
if(HSEStartUpStatus == SUCCESS)//HES就緒
{
RCC_HCLKConfig(RCC_SYSCLK_Div1);
//AHB時鐘(HCLK)=系統時鐘
RCC_PCLK1Config(RCC_HCLK_Div2);
//設置低速AHB時鐘(APB1)為HCLK的2分頻
RCC_PCLK2Config(RCC_HCLK_Div1);
//設置高速AHB時鐘(APB2)=HCLK時鐘
FLASH_SetLatency(FLASH_Latency_2);
//設置FLASH延時周期數為2
//使能領取指緩存
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//設置PLL時鐘源及倍頻系數,為HSE的9倍頻 8MHz * 9 = 72MHz
/*void RCC_PLLConfig(u32 RCC_PLLSource, u32 RCC_PLLMul)
RCC_PLLSource_HSI_Div2 pll輸入時鐘=hsi/2;
RCC_PLLSource_HSE_Div1 pll輸入時鐘 =hse
RCC_PLLSource_HSE_Div2 pll輸入時鐘=hse/2
RCC_PLLMul_2 ------_16 pll輸入時鐘*2---16
pll輸出時鐘不得超過72MHZ*/
RCC_PLLCmd(ENABLE);
//ENABLE / DISABLE
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);//等待PLL輸出穩定
/*FlagStatus RCC_GetFlagStatus(u8 RCC_FLAG) 檢查指定RCC標志位
返回SET OR RESET
RCC_FLAG_HSIRDY HSI晶振就緒
RCC_FLAG_HSERDY
RCC_FLAG_PLLRDY
RCC_FLAG_LSERDY
RCC_FLAG_LSIRDY.......*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//設置PLL為系統時鐘源
/*void RCC_SYSCLKConfig(u32 RCC_SYSCLKSource) 設置系統時鐘
RCC_SYSCLKSource_HSI
RCC_SYSCLKSource_HSE
RCC_SYSCLKSource_PLLCLK 選HSI HSE PLL 作為系統時鐘*/
while(RCC_GetSYSCLKSource() != 0x08);
//判斷PLL是否是系統時鐘
/*u8 RCC_GetSYSCLKSource(void) 返回用作系統時鐘的時鐘源
0x00:HSI 0x04:HSE 0x08:PLL */
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
RCC_APB2Periph_AFIO |
RCC_APB2Periph_GPIOB , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//U2 U3 時鐘在APB1
//打開GPIO時鐘,復用功能,串口1的時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1時鐘
//好奇怪,是因為官方的庫函數更新?
//不是說F10X系列只有一個CAN,而F4有CAN1 CAN2 嗎?
//怎么他的系統配置文件里面是can1?????
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //時鐘使能
/*void RCC_APB2PeriphClockCmd(u32 RCC_APB2Periph, FunctionalState NewState)
enable 或 disable apb2 外設時鐘
RCC_APB2Periph_AFIO 功能復用IO 時鐘
RCC_APB2Periph_GPIOA/B/C/D/E GPIOA/B/C/D/E 時鐘
RCC_APB2Periph_ADC1/ADC2 ADC1/2 時鐘
RCC_APB2Periph_TIM1
RCC_APB2Periph_SPI1
RCC_APB2Periph_USART1
RCC_APB2Periph_ALL 全部APB2外設時鐘*/
}
GPIO
#include "GPIO.h"
void MYGPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//GPIO_InitStructure初始化結構體為GPIO_InitTypeDef結構
GPIO_DeInit(GPIOA);
GPIO_StructInit(&GPIO_InitStructure);
//函數:指向結構GPIO_InitTypeDef的指針,待初始化
//CAN TX : A12
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
//CAN TX : A111
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
// USART TX :A9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
//2、GPIO_SPEED:GPIO_SPEED_10MHz/_2MHz/_50MHz 最高輸出速率
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
/*Mode,工作狀態:GPIO_MODE_AIN ----- 模擬輸入
_IN_FLOATING ----- 浮空輸入
_IPD ----- 上拉輸出
_IPU ----- 上拉輸入
_OUT_OD ----- 開漏輸出
_OUT_PP ----- 推挽輸出
_AF_OD ----- 復用開漏輸出
_AF_PP ----- 復用推挽輸出*/
GPIO_Init(GPIOA , &GPIO_InitStructure);
// USART RX :A10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//IO浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//初始化
/************pwm2 pa1**********************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
}
Delay
#include "delay.h"
static u8 fac_us=0; //us延時倍乘數
static u16 fac_ms=0; //ms延時倍乘數,在ucos下,代表每個節拍的ms數
//初始化延遲函數
//SYSTICK的時鐘固定為HCLK時鐘的1/8
//SYSCLK:系統時鐘
void delay_init()
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //選擇外部時鐘 HCLK/8
fac_us=SystemCoreClock/8000000; //為系統時鐘的1/8
fac_ms=(u16)fac_us*1000; //非OS下,代表每個ms需要的systick時鐘數
}
//延時nus
//nus為要延時的us數.
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //時間加載
SysTick->VAL=0x00; //清空計數器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待時間到達
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //關閉計數器
SysTick->VAL =0X00; //清空計數器
}
//延時nms
//注意nms的范圍
//SysTick->LOAD為24位寄存器,所以,最大延時為:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK單位為Hz,nms單位為ms
//對72M條件下,nms<=1864
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms; //時間加載(SysTick->LOAD為24bit)
SysTick->VAL =0x00; //清空計數器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待時間到達
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //關閉計數器
SysTick->VAL =0X00; //清空計數器
}
Led
#include "led.h"
//初始化PB12和13為輸出口.并使能這兩個口的時鐘
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB,PE端口時鐘
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根據設定參數初始化GPIOB
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);
}
Timer
#include "timer.h"
#include "led.h"
//定時器3中斷服務程序
void TIM2_IRQHandler(void) //TIM2中斷
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
//檢查指定的TIM中斷發生與否:TIM 中斷源
//不等于RESET 即為 SET,就是發生了
//(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update );
//清除TIMx的中斷待處理位:TIM 中斷源
LED0=!LED0;
}
}
//通用定時器3中斷初始化
//這里時鐘選擇為APB1的2倍,而APB1為36M
//arr:自動重裝值。
//psc:時鐘預分頻數
//TIMX X:1----4
//TIM2 PWM部分初始化
//PWM輸出初始化
//arr:自動重裝值
//psc:時鐘預分頻數
void TIM2_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/*typedef struct
{
u16 TIM_Period;
自動重裝寄存器周期的值,0x00000-----0xFFFF
u16 TIM_Prescaler;
TIMX 時鐘頻率除數的預分頻值 0x0000----0xFFFF
u8 TIM_ClockDivision;
時鐘分割 TIM_CKD_DIV1 T DTS = Tck_tim
TIM_CKD_DIV2 T DTS = 2Tck_tim
TIM_CKD_DIV4 T DTS = 4Tck_tim
u16 TIM_CounterMode;
計數器模式 TIM_CounterMode_Up TIM 向上計數模式
TIM_CounterMode_Down 向下計數模式
TIM_CounterMode_CenterAligned1 -----3 中央對齊模式1--3計數模式
} TIM_TimeBaseInitTypeDef;*/
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//初始化TIM2
TIM_TimeBaseStructure.TIM_Period = arr;
//設置在下一個更新事件裝入活動的自動重裝載寄存器 周期的值 就是周期 計數到5000為500ms
TIM_TimeBaseStructure.TIM_Prescaler =psc;
//設置用來作為TIMx時鐘頻率除數的預分頻值 10Khz的計數頻率
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//設置時鐘分割:T DTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//TIM向上計數模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
//根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM2中斷,允許更新中斷
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占優先級0級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //從優先級3級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器
TIM_Cmd(TIM2, ENABLE); //使能TIMx外設
//GPIO_PinRemapConfig(GPIO_PartialRemap2_TIM2, ENABLE); 怎么用????
//改變指定管腳的映射 Timer3部分重映射 TIM2_CH2->PB5
//初始化TIM2 Channel2 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//選擇定時器模式:TIM脈沖寬度調制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
//比較輸出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//輸出極性:TIM輸出比較極性高
//TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
//TIM_Pulse 待裝入比較寄存器的脈沖值 0x0000----0xFFFF
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
//根據T指定的參數初始化外設TIM2 OC2
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
//使能TIM2在CCR2上的預裝載寄存器
//TIM_ARRPreloadConfig(TIM2, ENABLE);
//使能TIM2在ARR上的預裝載寄存器
TIM_Cmd(TIM2, ENABLE); //使能TIM2
}
上一篇:STM32單片機—編碼器測速
下一篇:stm32F4編碼器測速并通過串口打印--- 程序源碼
推薦閱讀
史海拾趣
隨著公司規模的擴大和產品線的豐富,BusBoard公司開始積極尋求市場擴張的機會。通過與國內外知名電子設備制造商建立合作關系,BusBoard公司的產品逐漸打入國際市場。同時,公司還積極參與行業交流和展會,與同行分享經驗、探討合作,共同推動電子行業的發展。這種合作共贏的理念使得BusBoard公司在市場上獲得了更多的機會和資源。
AEM深知人才是企業發展的核心競爭力。因此,公司一直注重人才培養和團隊建設。AEM建立了完善的人才培養和激勵機制,吸引和培養了一批高素質、專業化的員工隊伍。同時,公司還為員工提供了良好的工作環境和發展空間,鼓勵員工不斷創新和進取。
在團隊建設方面,AEM注重團隊合作和溝通協作能力的培養。通過定期的團隊建設活動和內部培訓,AEM打造了一支團結、高效、富有戰斗力的團隊,為公司的持續發展提供了有力保障。
這五個故事從不同角度展示了AEM公司在電子行業中的發展歷程和取得的成就。通過不斷創新、合作與拓展,AEM已經成為電子行業中具有重要影響力的企業之一。未來,隨著技術的不斷進步和市場的不斷變化,AEM將繼續保持其領先地位,為電子行業的發展貢獻更多力量。
隨著科技的飛速發展,ATC公司始終保持著對技術創新的熱情與追求。公司不斷投入研發資源,引進先進設備和技術人才,致力于開發更具創新性和實用性的電子產品。經過多年的努力,ATC公司在多個技術領域取得了重要突破,推出了一系列具有行業影響力的創新產品,贏得了市場的廣泛認可。
作為一家多元化制造商,Dover Corporation一直致力于創新技術的研發與應用。公司在多個領域擁有先進的技術和解決方案,如先進的電梯控制系統、高效的燃料解決方案等。這些技術的應用不僅提高了Dover產品的性能和質量,也為客戶提供了更加優質的服務。
為了進一步擴大市場份額,Dover Corporation積極推進國際化布局。公司通過與國際、國內投行及私募基金的合作,成功收購了多家海外公司,實現了業務的全球化。這些收購不僅為Dover帶來了更多的市場機會,也增強了其在全球市場中的競爭力。
Hongfa宏發公司,全稱廈門宏發電聲股份有限公司,由郭滿金先生于1984年創立。公司初創時,僅有簡陋的廠房和設備,投資不過360萬元,員工僅數十人。但宏發從一開始就明確了產品定位與市場定位,專注于繼電器研發及制造領域。1987年,宏發成功以中國廠家商標及型號取得UL認證,進一步奠定了其在國際市場上的基礎。通過不斷的技術積累和市場開拓,宏發逐漸在國內繼電器行業中嶄露頭角。
DSP如果是以 111這種硬件模式從flash引導boot,那連接CCS后是否可以在燒寫程序進flash后,進行在線調試(在將程序從flash run 到ram 后)… 查看全部問答∨ |
請問大家,在BSP內核中加載I2C內核,在evc調用出現超時錯誤,這是怎么回事啊? I2C_Open ---- >I2C_IOControl(0x40004, 0x1a02f244, 16, 0x0) I2C IOCTL_I2C_WRITE 090704 I2C IOCTL_I2C_WRITE 090704 MapPtrToProcess +I2C_Write[1]: 0x9E, 0x1, 0x20, 1 EnterCriticalSection ResetEvent Be ResetEvent Af SyncIst ...… 查看全部問答∨ |
采用Marvell公司最新的基于第三代 Intel XScale 技術CPU PXA 310開發平臺 CES-310開發平臺簡介 深圳市海天雄電子有限公司 CES-310 開發平臺(實用型)簡介 ■ 功能與特色 CES-310 開發平臺采用Marvell公司最新的基于第三代 Intel XScale 技術CPU PXA 310 設計而成,本平臺在多媒體處理,速度等方面較之前推出的CPU 平臺 ...… 查看全部問答∨ |
|
我在程序中寫了這樣一段代碼。 clock_t start,stop,overhead; start=clock(); stop=clock(); overhead=stop-start; start=clock(); doSth(); stop=clock(); printf(\\"%d\\\\n\\",stop-start-overhead); 我發現輸出的結果總是0,調 ...… 查看全部問答∨ |
|
我的項目是手持產品,目前已經進入尾聲,但是在關機之后還會有約5個毫安的電流。請問如何解決?一般情況下,關機之后都進行那些處理才能達到TI宣稱的功耗值。???????!!!!!!… 查看全部問答∨ |
兩個CC2530模板,一個搭載MQ-2作為采集模塊(無線路由器),另一個作為接收模塊(協調器),實現兩者的通信并實現對煙霧信息的檢測,跪求大神幫忙解決!!!主要是程序,用IAR軟件!!!有相關資料的發郵箱554145080@qq.com,不勝感激!!!急需! ...… 查看全部問答∨ |
我用的是F122單片機,下面是我的程序,串口調試助手一直收不到數據,電路用的max3232,用示波器測它的輸出大概波形是有的,但是全是毛刺,好像噪聲很大的樣子。不知道是不是這個問題導致通信不成功。 #include void USART_Send(unsig ...… 查看全部問答∨ |