a total of 5 16-bit timers in the s3c2440 chip, of which 4 timers (timer 0~timer 3) have pulse width modulation function, so PWM function can be easily implemented using s3c2440. The following is a detailed introduction on how to implement the PWM function.
1. PWM is output through pins TOUT0~TOUT3, and these 4 pins are multiplexed with GPB0~GPB3. Therefore, to implement the PWM function, the corresponding pins must first be configured as TOUT output.
2. Then set the output clock frequency of the timer, which is based on PCLK, and then divided by the prescaler parameter configured with register TCFG0 and the divider parameter configured with register TCFG1.
3. Then set the specific width of the pulse. Its basic principle is to configure the count of register TCNTn (internal register) through register TCNTBn. TCNTn is decremented. If it is reduced to zero, it will reload the number in TCNTBn and start counting again. Register TCMPBn is used as a comparison register to compare with the count value. When TCNTn is equal to TCMPBn, the level of TOUTn output will flip, and when TCNTn is reduced to zero, the level will flip again, and it will be repeated. Therefore, the key to this step is to set registers TCNTBn and TCMPBn. The former can determine the length of a counting cycle, and the latter can determine the duty cycle of the square wave. Since the timer of s3c2440 has double buffering, the values of these two registers can be changed while the timer is running, and it will be effective at the beginning of the next cycle.
4. Finally, it is the control of PWM, which is realized through the register TCON. Generally speaking, each timer has 4 bits to be configured (timer 0 has one more dead zone bit): start/stop bit, used to start and stop the timer; manual update bit, used to manually update TCNTBn and TCMPBn. It should be noted here that when starting the timing, this bit must be cleared to zero, otherwise the timer cannot be started; output inversion bit, used to change the output level direction, so that the original high-level output becomes a low level, and the low level becomes a high level; automatic reload bit, used to reload the value in TCNTBn after TCNTn is reduced to zero. When you don’t want to count, you can make the automatic reload invalid, so that after TCNTn is reduced to zero, no new number will be loaded to it, then the TOUTn output will always maintain a level (when the output inversion bit is 0, it is a high-level output; when the output inversion bit is 1, it is a low-level output), so there is no PWM function, so this bit can be used to stop PWM.
PWM has many uses. Here I use the resources of the development board to drive a buzzer and change the frequency of the buzzer by changing the pulse width. The following program uses PWM to drive the buzzer. The pulse width goes from low to high, then from high to low, over and over again. We also use 4 LEDs to indicate the frequency. When the frequency is the highest, all LEDs are on, and when the frequency is the lowest, all LEDs are off. And we use two buttons to pause the buzzer and restart the buzzer respectively:
#define _ISR_STARTADDRESS 0x33ffff00
#define U32 unsigned int
typedef unsigned char BOOL;
#define TRUE 1
#define FALSE 0
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
#define pISR_EINT1 (*(unsigned *)(_ISR_STARTADDRESS+0x24))
#define rSRCPND (*(volatile unsigned *)0x4a000000) //Interrupt request status
#define rINTMSK (*(volatile unsigned *)0x4a000008) //Interrupt mask control
#define rINTPND (*(volatile unsigned *)0x4a000010) //Interrupt request status
#define rGPBCON (*(volatile unsigned *)0x56000010) //Port B control
#define rGPBDAT (*(volatile unsigned *)0x56000014) //Port B data
#define rGPBUP (*(volatile unsigned *)0x56000018) //Pull-up control B
#define rGPFCON (*(volatile unsigned *)0x560 00050) //Port F control
#define rEXTINT0 (*(volatile unsigned *)0x56000088) //External interrupt control register 0
#define rTCFG0 (*(volatile unsigned *)0x51000000) //Timer configuration
#define rTCFG1 (*(volatile unsigned *)0x51000004) //Timer configuration
#define rTCON (*(vola tile unsigned *)0x51000008) //Timer control
#define rTCNTB0 (*(volatile unsigned *)0x5100000c) //Timer count buffer 0
#define rTCMPB0 (*(volatile unsigned *)0x51000010) //Timer compare buffer 0
BOOL stop;
static void __irq Key1_ISR(void) //Pause key, turn off the buzzer
{
rSRCPND = rSRCPND | (0x1<<1);
rINTPND = rINTPND | (0x1<<1);
rTCON &= ~0x8; //Disable timer auto-reload, that is, turn off the timer
stop = TRUE;
}
void __irq Key4_ISR(void) //Restart key, turn on the buzzer
{
rSRCPND = rSRCPND | 0x1;
rINTPND = rINTPND | 0x1;
stop = FALSE;
}
void delay(int a)
{
int k;
for(k=0;k ;
}
void Main(void)
{
int freq;
rGPBCON = 0x155556; //B0 is TOUT0, B5~B8 are outputs, for LED
rGPBUP = 0x7ff;
rGPFCON = 0xaaaa; //Port F is EINT, for the button
//Some necessary configurations of the button
rSRCPND = 0x07;
rINTMSK = ~0x07;
rINTPND =0x07;
rEXTINT0 = 0x22;
freq = 2500;
rTCFG0 &= 0xFFFF00;
rTCFG0 |= 0x31; //prescal is 49
rTCFG1 &= ~0xF; //1/2, because PCLK is 50MHz, so 50MHz/50/2=500kHz
rTCNTB0 = 5000;
rTCMPB0 = freq;
rTCON &= ~0x1F;
rTCON |= 0xf; //dead zone invalid, automatic load, level inversion, manual update, timer start
rTCON &= ~0x2; //manual update bit cleared, PWM starts working
pISR_EINT0 = (U32)Key4_ISR;
pISR_EINT1 = (U32)Key1_ISR;
stop = FALSE;
rGPBDAT = ~0x60; //two LEDs are on
while(1)
{
//frequency increment
for (; freq<4950; )
{
freq+=10;
rTCMPB0 = freq; //Reassign
delay(20000);
while (stop == TRUE) //Pause
{
delay(1000);
if (stop ==FALSE) //Judge whether to restart
{
rTCON &= ~0x1F;
rTCON |= 0xf;
rTCON &= ~0x2 ; //Restore PWM function
}
}
//The 4 LEDs turn on and off depending on the frequencyif
(freq == 100)
rGPBDAT = ~0x1e0;
if(freq == 1300)
rGPBDAT = ~0xe0;
if(freq == 2500)
rGPBDAT = ~0x60;
if(freq == 3700)
rGPBDAT = ~0x20;
if(freq == 4900)
rGPBDAT = ~0x0;
}
//Frequency decrease
for( ; freq>50 ; )
{
freq-=10;
rTCMPB0 = freq;
delay(20000);
while (stop == TRUE)
{
delay(1000);
if (stop ==FALSE)
{
rTCON &= ~0x1F;
rTCON |= 0xf;
rTCON &= ~0x2 ;
}
}
if(freq == 100)
rGPBDAT = ~0x1e0;
if(freq == 1300)
rGPBDAT = ~0xe0;
if(freq == 2500)
rGPBDAT = ~0x60;
if(freq == 3700)
rGPBDAT = ~0x20;
if(freq == 4900)
rGPBDAT = ~0x0;
}
}
}
There are a few points to note here:
1. The buzzer on the development board sounds when the level is high and stops when the level is low. When the TOUT0 timing is invalid, the output is high. Therefore, in order to make the buzzer stop sounding when the PWM is invalid, I reversed the output level (set the output inversion bit in TCON);
2. Here, I jump out of the while loop by pressing the stop flag variable to FALSE and restart the buzzer, but for some reason, if I don’t add a waiting time in the while loop, I can never jump out of the loop body, so I have to add a delay function to let it wait for a while. I can’t give a satisfactory explanation for this problem, and I don’t know where the problem is!
Previous article:Application of s3c2440 timer interrupt
Next article:s3c2440 external interrupt operation
Recommended ReadingLatest update time:2024-11-16 19:55
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- One week evaluation information, delivered on time~
- Tips for selecting brushless DC motor driver chips
- EEWORLD University Hall----Live Replay: TI 60G mmWave Sensor Overview and Application Introduction
- Full-wave precision rectifier circuit composed of comparators
- NUCLEO-474 Download the official example prompt No debug probe... Solution
- SERDES interface circuit design
- TMS320C55x DSP Library
- Antenna Basics and Introduction to 40+ Antennas
- USB interface reading and writing design based on FPGA.pdf
- Brief analysis: RF power meter principle, classification, index and application