Function: The STC12C2052AD microcontroller successfully implements an ADC conversion C program along with PWM output functionality.
Application: It is used for voltage detection, overvoltage protection (via relay control), and converting DC voltage into pulsating DC using PWM chopping.
Board Function: This board is designed to charge a phone battery.
For the LM317 buck converter, a small current application should be sufficient. Since there was no time to purchase a switch transistor, a 9013 transistor was used instead.
Drawing:
//The following is a successful program. If you need to apply it to your own project, you only need to change the IO pins accordingly.
//Full version of the program download address:
#include //Special header file for STC microcontroller
#include
#define uchar unsigned char
#define uint unsigned int
#define AD_SPEED 0x60 //0110,0000 - 270 clock cycles for conversion
/************ Hebei is waiting for you! &&&& less fish welcome you! ******************************/
//
sbit M = P1^5; //Overvoltage indicator
sbit N = P1^3; //Undervoltage indicator
sbit LED = P1^7; //Working status indicator
sbit CONTRL = P3^4; //Output control
sbit PWM = P3^7;
/************************************************* ***************/
void pwm();
void delayms(uint);
uint ADC();
void InitADC();
void baohu();
float voltage = 0.0;
uint V;
float VCC = 5.05;
uchar mtab[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
/***8********************************************* *****************/
void main()
{
CONTRL = 0; //First close the output
delayms(700);
V = 40; //These are added when I made a mistake. The purpose is to figure out exactly what AD has converted.
voltage = 4.0; //Practical proof, the replacement value is useless, indicating no AD
LED = 0;
CONTRL = 1;
voltage = V * VCC / 256.00 * 5.00;
delayms(1000);
PWM = 1;
CONTRL = 1; //Relay is working, in protection mode
delayms(1000);
M = 0;
N = 0;
LED = 0;
delayms(2000);
M = 1;
N = 1;
LED = 1;
pwm(); //Generate PWM waveform
delayms(7000);
delayms(100); //Delay
InitADC();
delayms(20);
V = ADC();
baohu();
while(1)
{
V = ADC();
baohu();
delayms(300);
}
}
//
//
void pwm()
{
//PCA module works in PWM mode
CMOD = 0x04; //Use timer 0 overflow for PCA pulse
CL = 0x00; //PCA timer low 8 bits (Address: E9H)
CH = 0x00; //PCA high 8-bit address (F9H)
CCON = 0x00;
CCAP0L = 0x60; //Control duty cycle in PWM mode
CCAP0H = 0x60; //0xff-0xc0=0x3f, 64/256=25% duty cycle (overflow)
CCAPM0 = 0x42; //Set PCA module 0 to PWM mode
//ECOM0=1 enable compare, PWM0=1 enable CEX0 pin as pulse width adjustment output
/*********************
PCA module working mode setting (CCAPMn register, n = 0-3)
7 6 5 4 3 2 1 0
- ECOMn CAPPn CAPNn MATn TOGn PWMn ECCFn
Options: 0x00 no action
0x20 16-bit capture mode, triggered by CEXn rising edge
0x10 16-bit capture mode, triggered by CEXn falling edge
0x30 16-bit capture mode, triggered by CEXn transition
0x48 16-bit software timer
0x4c 16-bit high speed output
0x42 8-bit PWM output
Each PCA module has two registers: CCAPnH and CCAPnL. They store 16-bit count values used for capturing or comparing, and control the duty cycle when operating in PWM mode.
*******************************/
TMOD = 0x02;
TH0 = 0x06;
TL0 = 0x06;
CR = 1; //Start PCA Timer
TR0 = 1;
}
//ADC conversion initialization - turn on ADC power supply
void InitADC()
{
P1 = 0xff;
ADC_CONTR |= 0x80;
delayms(80);
//These two registers are used to set the four states of the P1 port, each bit corresponds to a P1 pin, combined operation based on state
/*****************
P1M0 and P1M1 register bits 7 6 5 4 3 2 1 0
P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 P1.0
The same applies to P3M0 and P3M1. Since the STC12C2052AD only has two P ports, there are only two groups of P1M0 and P1M1. For other models like STC12C5410AD, there are three groups.
P1M0 and P1M1 high
0 0 Normal I/O port (quasi-bidirectional)
0 1 Strong push-pull output (20mA current)
1 0 Input mode available for A/D conversion
1 1 Open drain, available for A/D conversion
Example:
To set P1.2 as an AD input port:
P1M0 = 0x02;
P1M1 = 0x02; //Open drain
When not using ADC, it's best to turn off the ADC power and restore to the I/O port state.
********************************/
P1M0 = 0x02; //Set P1.1 to open drain state
P1M1 = 0x02;
}
//ADC conversion program
/************************************************* *****
Note: The commands commented in this function are general commands that can be used for all AD channels. I have identified a specific channel (P1.1), so I directly assigned it to save "flow". The problem I encountered was the while loop in this function.
While (1) //Wait for the end of the A/D conversion
{
If (ADC_CONTR & 0x10) //Test if A/D conversion is complete
{ break; }
}
This works, but what I originally wrote was:
While (ADC_CONTR & 0x10 == 0);
This is incorrect because the precedence of '==' is higher than '&'.
So add brackets:
While ((ADC_CONTR & 0x10) == 0);
If you're not familiar with C, you might forget this!
A lesson learned from this: small problems can affect efficiency.
Experience: Adding brackets often helps avoid issues without consuming "flow"!
*********************************************/
uint ADC()
{
ADC_DATA = 0; //Clear result
ADC_CONTR = 0x60; //Set conversion speed to fastest
ADC_CONTR = 0xE0; //Clear ADC_FLAG, ADC_START bit, and lower 3 bits
ADC_CONTR = 0xe1;
//ADC_CONTR |= 0x01; //Select A/D channel P1.1
delayms(1); //Stabilize input voltage
ADC_CONTR = 0xe9;
//ADC_CONTR |= 0x08; //Start A/D conversion
While (1) //Wait for A/D conversion to finish
{
If (ADC_CONTR & 0x10) //Check if A/D conversion is done
{ break; }
}
ADC_CONTR = 0xe1;
//ADC_CONTR &= 0xE7; //Clear ADC_FLAG, disable A/D conversion
return ADC_DATA; //Return 10-bit A/D conversion result
}
//
void baohu()
{
voltage = V * VCC / 256.00 * 5.00;
if(voltage > 5.25)
{
CONTRL = 1; //Overvoltage protection, turn off the switch tube control
M = 0;
N = 1;
LED = 1;
}
if(voltage < 4.62 && voltage > 4.50)
Silicone rubble cold shrinkable tube
Dongguan Zhonghe Electronics Co., Ltd. , https://www.zhonghesleeving.com